msvcrt: Test and fix _mbccpy, _mbsncpy and _mbsnbcpy.
[wine] / dlls / msvcrt / tests / string.c
1 /*
2  * Unit test suite for string functions.
3  *
4  * Copyright 2004 Uwe Bonnes
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "wine/test.h"
22 #include "winbase.h"
23 #include <string.h>
24 #include <mbstring.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <mbctype.h>
28 #include <locale.h>
29
30 static char *buf_to_string(const unsigned char *bin, int len, int nr)
31 {
32     static char buf[2][1024];
33     char *w = buf[nr];
34     int i;
35
36     for (i = 0; i < len; i++)
37     {
38         sprintf(w, "%02x ", (unsigned char)bin[i]);
39         w += strlen(w);
40     }
41     return buf[nr];
42 }
43
44 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
45 #define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len, 1), buf_to_string((buf), len, 0)); }
46
47 static void* (*pmemcpy)(void *, const void *, size_t n);
48 static int* (*pmemcmp)(void *, const void *, size_t n);
49
50 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y)
51 #define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y)
52
53 HMODULE hMsvcrt;
54
55 static void test_swab( void ) {
56     char original[]  = "BADCFEHGJILKNMPORQTSVUXWZY@#";
57     char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#";
58     char expected2[] = "ABCDEFGHIJKLMNOPQRSTUVWX$";
59     char expected3[] = "$";
60     
61     char from[30];
62     char to[30];
63     
64     int testsize;
65     
66     /* Test 1 - normal even case */                               
67     memset(to,'$', sizeof(to));
68     memset(from,'@', sizeof(from));
69     testsize = 26;
70     memcpy(from, original, testsize);
71     _swab( from, to, testsize );
72     ok(memcmp(to,expected1,testsize) == 0, "Testing even size %d returned '%*.*s'\n", testsize, testsize, testsize, to);
73
74     /* Test 2 - uneven case  */                               
75     memset(to,'$', sizeof(to));
76     memset(from,'@', sizeof(from));
77     testsize = 25;
78     memcpy(from, original, testsize);
79     _swab( from, to, testsize );
80     ok(memcmp(to,expected2,testsize) == 0, "Testing odd size %d returned '%*.*s'\n", testsize, testsize, testsize, to);
81
82     /* Test 3 - from = to */                               
83     memset(to,'$', sizeof(to));
84     memset(from,'@', sizeof(from));
85     testsize = 26;
86     memcpy(to, original, testsize);
87     _swab( to, to, testsize );
88     ok(memcmp(to,expected1,testsize) == 0, "Testing overlapped size %d returned '%*.*s'\n", testsize, testsize, testsize, to);
89
90     /* Test 4 - 1 bytes */                               
91     memset(to,'$', sizeof(to));
92     memset(from,'@', sizeof(from));
93     testsize = 1;
94     memcpy(from, original, testsize);
95     _swab( from, to, testsize );
96     ok(memcmp(to,expected3,testsize) == 0, "Testing small size %d returned '%*.*s'\n", testsize, testsize, testsize, to);
97 }
98
99 #if 0      /* use this to generate more tests */
100
101 static void test_codepage(int cp)
102 {
103     int i;
104     int prev;
105     int count = 1;
106
107     ok(_setmbcp(cp) == 0, "Couldn't set mbcp\n");
108
109     prev = _mbctype[0];
110     printf("static int result_cp_%d_mbctype[] = { ", cp);
111     for (i = 1; i < 257; i++)
112     {
113         if (_mbctype[i] != prev)
114         {
115             printf("0x%x,%d, ", prev, count);
116             prev = _mbctype[i];
117             count = 1;
118         }
119         else
120             count++;
121     }
122     printf("0x%x,%d };\n", prev, count);
123 }
124
125 #define test_codepage_todo(cp, todo) test_codepage(cp)
126
127 #else
128
129 /* RLE-encoded mbctype tables for given codepages */
130 static int result_cp_1252_mbctype[] = { 0x0,66, 0x10,26, 0x0,6, 0x20,26, 0x0,8, 0x20,1,
131   0x0,6, 0x10,1, 0x0,1, 0x10,1, 0x0,1, 0x10,1, 0x0,11, 0x20,1, 0x0,1, 0x20,1, 0x0,1,
132   0x20,1, 0x10,1, 0x0,10, 0x20,1, 0x0,10, 0x20,1, 0x0,4, 0x20,1, 0x0,5, 0x10,23, 0x0,1,
133   0x10,7, 0x20,24, 0x0,1, 32,8 };
134 static int result_cp_1250_mbctype[] = { 0x0,66, 0x10,26, 0x0,6, 0x20,26, 0x0,15, 0x10,1,
135   0x0,1, 0x10,4, 0x0,10, 0x20,1, 0x0,1, 0x20,4, 0x0,3, 0x10,1, 0x0,1, 0x10,1, 0x0,4,
136   0x10,1, 0x0,4, 0x10,1, 0x0,3, 0x20,1, 0x0,1, 0x20,1, 0x0,3, 0x20,2, 0x0,1, 0x10,1,
137   0x0,1, 0x20,2, 0x10,23, 0x0,1, 0x10,7, 0x20,24, 0x0,1, 0x20,7, 0,1 };
138 static int result_cp_932_mbctype[] = { 0x0,65, 0x8,1, 0x18,26, 0x8,6, 0x28,26, 0x8,4,
139   0x0,1, 0x8,1, 0xc,31, 0x8,1, 0xa,5, 0x9,58, 0xc,29, 0,3 };
140 static int result_cp_936_mbctype[] = { 0x0,65, 0x8,1, 0x18,26, 0x8,6, 0x28,26, 0x8,6,
141   0xc,126, 0,1 };
142 static int result_cp_949_mbctype[] = { 0x0,66, 0x18,26, 0x8,6, 0x28,26, 0x8,6, 0xc,126,
143   0,1 };
144 static int result_cp_950_mbctype[] = { 0x0,65, 0x8,1, 0x18,26, 0x8,6, 0x28,26, 0x8,4,
145   0x0,2, 0x4,32, 0xc,94, 0,1 };
146 static int result_cp_20932_mbctype[] = { 0x0,2, 0x8,64, 0x18,26, 0x8,6, 0x28,26, 0x8,19,
147   0xc,1, 0x8,18, 0xc,94, 0,1 };
148
149 static int todo_none[] = { -2 };
150 static int todo_cp_932[] = { 254, -2 };
151 static int todo_cp_20932[] = { 143, -2 };
152
153 void test_cp_table(int cp, int *result, int *todo)
154 {
155     int i;
156     int count = 0;
157     int curr = 0;
158     _setmbcp(cp);
159     for (i = 0; i < 256; i++)
160     {
161         if (count == 0)
162         {
163             curr = result[0];
164             count = result[1];
165             result += 2;
166         }
167         if (i == *todo + 1)
168         {
169             todo_wine ok(_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, _mbctype[i], curr);
170             todo++;
171         }
172         else
173             ok(_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, _mbctype[i], curr);
174         count--;
175     }
176 }
177
178 #define test_codepage(num) test_cp_table(num, result_cp_##num##_mbctype, todo_none);
179 #define test_codepage_todo(num, todo) test_cp_table(num, result_cp_##num##_mbctype, todo);
180
181 #endif
182
183 static void test_mbcp(void)
184 {
185     int mb_orig_max = __mb_cur_max;
186     int curr_mbcp = _getmbcp();
187     unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2 \xb3\xb4 \xb5"; /* incorrect string */
188     unsigned char *mbstring2 = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5"; /* correct string */
189     unsigned char *mbsonlylead = (unsigned char *)"\xb0\0\xb1\xb2";
190     unsigned char buf[16];
191
192     /* some two single-byte code pages*/
193     test_codepage(1252);
194     test_codepage(1250);
195     /* double byte code pages */
196     test_codepage_todo(932, todo_cp_932);
197     test_codepage(936);
198     test_codepage(949);
199     test_codepage(950);
200     test_codepage_todo(20932, todo_cp_20932);
201
202     _setmbcp(936);
203     ok(__mb_cur_max == mb_orig_max, "__mb_cur_max shouldn't be updated (is %d != %d)\n", __mb_cur_max, mb_orig_max);
204     ok(_ismbblead('\354'), "\354 should be a lead byte\n");
205     ok(_ismbblead(' ') == FALSE, "' ' should not be a lead byte\n");
206     ok(_ismbblead(0x1234b0), "0x1234b0 should not be a lead byte\n");
207     ok(_ismbblead(0x123420) == FALSE, "0x123420 should not be a lead byte\n");
208     ok(_ismbbtrail('\xb0'), "\xa0 should be a trail byte\n");
209     ok(_ismbbtrail(' ') == FALSE, "' ' should not be a trail byte\n");
210
211     /* _mbsnextc */
212     expect_eq(_mbsnextc(mbstring), 0xb0b1, int, "%x");
213     expect_eq(_mbsnextc(&mbstring[2]), 0xb220, int, "%x");  /* lead + invalid tail */
214     expect_eq(_mbsnextc(&mbstring[3]), 0x20, int, "%x");    /* single char */
215
216     /* _mbclen/_mbslen */
217     expect_eq(_mbclen(mbstring), 2, int, "%d");
218     expect_eq(_mbclen(&mbstring[2]), 2, int, "%d");
219     expect_eq(_mbclen(&mbstring[3]), 1, int, "%d");
220     expect_eq(_mbslen(mbstring2), 4, int, "%d");
221     expect_eq(_mbslen(mbsonlylead), 0, int, "%d");          /* lead + NUL not counted as character */
222     expect_eq(_mbslen(mbstring), 4, int, "%d");             /* lead + invalid trail counted */
223
224     /* _mbccpy/_mbsncpy */
225     memset(buf, 0xff, sizeof(buf));
226     _mbccpy(buf, mbstring);
227     expect_bin(buf, "\xb0\xb1\xff", 3);
228
229     memset(buf, 0xff, sizeof(buf));
230     _mbsncpy(buf, mbstring, 1);
231     expect_bin(buf, "\xb0\xb1\xff", 3);
232     memset(buf, 0xff, sizeof(buf));
233     _mbsncpy(buf, mbstring, 2);
234     expect_bin(buf, "\xb0\xb1\xb2 \xff", 5);
235     memset(buf, 0xff, sizeof(buf));
236     _mbsncpy(buf, mbstring, 3);
237     expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4\xff", 7);
238     memset(buf, 0xff, sizeof(buf));
239     _mbsncpy(buf, mbstring, 4);
240     expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \xff", 8);
241     memset(buf, 0xff, sizeof(buf));
242     _mbsncpy(buf, mbstring, 5);
243     expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \0\0\xff", 10);
244     memset(buf, 0xff, sizeof(buf));
245     _mbsncpy(buf, mbsonlylead, 6);
246     expect_bin(buf, "\0\0\0\0\0\0\0\xff", 8);
247
248     memset(buf, 0xff, sizeof(buf));
249     _mbsnbcpy(buf, mbstring2, 2);
250     expect_bin(buf, "\xb0\xb1\xff", 3);
251     _mbsnbcpy(buf, mbstring2, 3);
252     expect_bin(buf, "\xb0\xb1\0\xff", 4);
253     _mbsnbcpy(buf, mbstring2, 4);
254     expect_bin(buf, "\xb0\xb1\xb2\xb3\xff", 5);
255     memset(buf, 0xff, sizeof(buf));
256     _mbsnbcpy(buf, mbsonlylead, 5);
257     expect_bin(buf, "\0\0\0\0\0\xff", 6);
258
259     /* functions that depend on locale codepage, not mbcp.
260      * we hope the current locale to be SBCS because setlocale(LC_ALL, ".1252") seems not to work yet
261      * (as of Wine 0.9.43)
262      */
263     if (__mb_cur_max == 1)
264     {
265         expect_eq(mblen((char *)mbstring, 3), 1, int, "%x");
266         expect_eq(_mbstrlen((char *)mbstring2), 7, int, "%d");
267     }
268     else
269         skip("Current locale has double-byte charset - could leave to false positives\n");
270
271     _setmbcp(curr_mbcp);
272 }
273
274 static void test_mbsspn( void)
275 {
276     unsigned char str1[]="cabernet";
277     unsigned char str2[]="shiraz";
278     unsigned char set[]="abc";
279     unsigned char empty[]="";
280     int ret;
281     ret=_mbsspn( str1, set);
282     ok( ret==3, "_mbsspn returns %d should be 3\n", ret);
283     ret=_mbsspn( str2, set);
284     ok( ret==0, "_mbsspn returns %d should be 0\n", ret);
285     ret=_mbsspn( str1, empty);
286     ok( ret==0, "_mbsspn returns %d should be 0\n", ret);
287 }
288
289 static void test_mbsspnp( void)
290 {
291     unsigned char str1[]="cabernet";
292     unsigned char str2[]="shiraz";
293     unsigned char set[]="abc";
294     unsigned char empty[]="";
295     unsigned char full[]="abcenrt";
296     unsigned char* ret;
297     ret=_mbsspnp( str1, set);
298     ok( ret[0]=='e', "_mbsspnp returns %c should be e\n", ret[0]);
299     ret=_mbsspnp( str2, set);
300     ok( ret[0]=='s', "_mbsspnp returns %c should be s\n", ret[0]);
301     ret=_mbsspnp( str1, empty);
302     ok( ret[0]=='c', "_mbsspnp returns %c should be c\n", ret[0]);
303     ret=_mbsspnp( str1, full);
304     ok( ret==NULL, "_mbsspnp returns %p should be NULL\n", ret);
305 }
306
307 static void test_strdup(void)
308 {
309    char *str;
310    str = _strdup( 0 );
311    ok( str == 0, "strdup returns %s should be 0\n", str);
312    free( str );
313 }
314
315 START_TEST(string)
316 {
317     void *mem;
318     static const char xilstring[]="c:/xilinx";
319     int nLen;
320
321     hMsvcrt = GetModuleHandleA("msvcrt.dll");
322     if (!hMsvcrt)
323         hMsvcrt = GetModuleHandleA("msvcrtd.dll");
324     ok(hMsvcrt != 0, "GetModuleHandleA failed\n");
325     SET(pmemcpy,"memcpy");
326     SET(pmemcmp,"memcmp");
327
328     /* MSVCRT memcpy behaves like memmove for overlapping moves,
329        MFC42 CString::Insert seems to rely on that behaviour */
330     mem = malloc(100);
331     ok(mem != NULL, "memory not allocated for size 0\n");
332     strcpy((char*)mem,xilstring);
333     nLen=strlen(xilstring);
334     pmemcpy((char*)mem+5, mem,nLen+1);
335     ok(pmemcmp((char*)mem+5,xilstring, nLen) == 0, 
336        "Got result %s\n",(char*)mem+5);
337
338     /* Test _swab function */
339     test_swab();
340
341     /* Test ismbblead*/
342     test_mbcp();
343    /* test _mbsspn */
344     test_mbsspn();
345     test_mbsspnp();
346    /* test _strdup */
347     test_strdup();
348 }