msvcrt: Test and fix _mbsinc/_mbsninc.
[wine.git] / dlls / msvcrt / tests / string.c
blob004d059c6f828251f1480d8f721488f3a8a93fef
1 /*
2 * Unit test suite for string functions.
4 * Copyright 2004 Uwe Bonnes
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.
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.
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
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>
30 static char *buf_to_string(const unsigned char *bin, int len, int nr)
32 static char buf[2][1024];
33 char *w = buf[nr];
34 int i;
36 for (i = 0; i < len; i++)
38 sprintf(w, "%02x ", (unsigned char)bin[i]);
39 w += strlen(w);
41 return buf[nr];
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)); }
47 static void* (*pmemcpy)(void *, const void *, size_t n);
48 static int* (*pmemcmp)(void *, const void *, size_t n);
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)
53 HMODULE hMsvcrt;
55 static void test_swab( void ) {
56 char original[] = "BADCFEHGJILKNMPORQTSVUXWZY@#";
57 char expected1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ@#";
58 char expected2[] = "ABCDEFGHIJKLMNOPQRSTUVWX$";
59 char expected3[] = "$";
61 char from[30];
62 char to[30];
64 int testsize;
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);
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);
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);
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);
99 #if 0 /* use this to generate more tests */
101 static void test_codepage(int cp)
103 int i;
104 int prev;
105 int count = 1;
107 ok(_setmbcp(cp) == 0, "Couldn't set mbcp\n");
109 prev = _mbctype[0];
110 printf("static int result_cp_%d_mbctype[] = { ", cp);
111 for (i = 1; i < 257; i++)
113 if (_mbctype[i] != prev)
115 printf("0x%x,%d, ", prev, count);
116 prev = _mbctype[i];
117 count = 1;
119 else
120 count++;
122 printf("0x%x,%d };\n", prev, count);
125 #define test_codepage_todo(cp, todo) test_codepage(cp)
127 #else
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 };
147 static int todo_none[] = { -2 };
148 static int todo_cp_932[] = { 254, -2 };
150 void test_cp_table(int cp, int *result, int *todo)
152 int i;
153 int count = 0;
154 int curr = 0;
155 _setmbcp(cp);
156 for (i = 0; i < 256; i++)
158 if (count == 0)
160 curr = result[0];
161 count = result[1];
162 result += 2;
164 if (i == *todo + 1)
166 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);
167 todo++;
169 else
170 ok(_mbctype[i] == curr, "CP%d: Mismatch in ctype for character %d - %d instead of %d\n", cp, i-1, _mbctype[i], curr);
171 count--;
175 #define test_codepage(num) test_cp_table(num, result_cp_##num##_mbctype, todo_none);
176 #define test_codepage_todo(num, todo) test_cp_table(num, result_cp_##num##_mbctype, todo);
178 #endif
180 static void test_mbcp(void)
182 int mb_orig_max = __mb_cur_max;
183 int curr_mbcp = _getmbcp();
184 unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2 \xb3\xb4 \xb5"; /* incorrect string */
185 unsigned char *mbstring2 = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5"; /* correct string */
186 unsigned char *mbsonlylead = (unsigned char *)"\xb0\0\xb1\xb2";
187 unsigned char buf[16];
188 int step;
190 /* some two single-byte code pages*/
191 test_codepage(1252);
192 test_codepage(1250);
193 /* double byte code pages */
194 test_codepage_todo(932, todo_cp_932);
195 test_codepage(936);
196 test_codepage(949);
197 test_codepage(950);
199 _setmbcp(936);
200 ok(__mb_cur_max == mb_orig_max, "__mb_cur_max shouldn't be updated (is %d != %d)\n", __mb_cur_max, mb_orig_max);
201 ok(_ismbblead('\354'), "\354 should be a lead byte\n");
202 ok(_ismbblead(' ') == FALSE, "' ' should not be a lead byte\n");
203 ok(_ismbblead(0x1234b0), "0x1234b0 should not be a lead byte\n");
204 ok(_ismbblead(0x123420) == FALSE, "0x123420 should not be a lead byte\n");
205 ok(_ismbbtrail('\xb0'), "\xa0 should be a trail byte\n");
206 ok(_ismbbtrail(' ') == FALSE, "' ' should not be a trail byte\n");
208 /* _mbsnextc */
209 expect_eq(_mbsnextc(mbstring), 0xb0b1, int, "%x");
210 expect_eq(_mbsnextc(&mbstring[2]), 0xb220, int, "%x"); /* lead + invalid tail */
211 expect_eq(_mbsnextc(&mbstring[3]), 0x20, int, "%x"); /* single char */
213 /* _mbclen/_mbslen */
214 expect_eq(_mbclen(mbstring), 2, int, "%d");
215 expect_eq(_mbclen(&mbstring[2]), 2, int, "%d");
216 expect_eq(_mbclen(&mbstring[3]), 1, int, "%d");
217 expect_eq(_mbslen(mbstring2), 4, int, "%d");
218 expect_eq(_mbslen(mbsonlylead), 0, int, "%d"); /* lead + NUL not counted as character */
219 expect_eq(_mbslen(mbstring), 4, int, "%d"); /* lead + invalid trail counted */
221 /* _mbccpy/_mbsncpy */
222 memset(buf, 0xff, sizeof(buf));
223 _mbccpy(buf, mbstring);
224 expect_bin(buf, "\xb0\xb1\xff", 3);
226 memset(buf, 0xff, sizeof(buf));
227 _mbsncpy(buf, mbstring, 1);
228 expect_bin(buf, "\xb0\xb1\xff", 3);
229 memset(buf, 0xff, sizeof(buf));
230 _mbsncpy(buf, mbstring, 2);
231 expect_bin(buf, "\xb0\xb1\xb2 \xff", 5);
232 memset(buf, 0xff, sizeof(buf));
233 _mbsncpy(buf, mbstring, 3);
234 expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4\xff", 7);
235 memset(buf, 0xff, sizeof(buf));
236 _mbsncpy(buf, mbstring, 4);
237 expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \xff", 8);
238 memset(buf, 0xff, sizeof(buf));
239 _mbsncpy(buf, mbstring, 5);
240 expect_bin(buf, "\xb0\xb1\xb2 \xb3\xb4 \0\0\xff", 10);
241 memset(buf, 0xff, sizeof(buf));
242 _mbsncpy(buf, mbsonlylead, 6);
243 expect_bin(buf, "\0\0\0\0\0\0\0\xff", 8);
245 memset(buf, 0xff, sizeof(buf));
246 _mbsnbcpy(buf, mbstring2, 2);
247 expect_bin(buf, "\xb0\xb1\xff", 3);
248 _mbsnbcpy(buf, mbstring2, 3);
249 expect_bin(buf, "\xb0\xb1\0\xff", 4);
250 _mbsnbcpy(buf, mbstring2, 4);
251 expect_bin(buf, "\xb0\xb1\xb2\xb3\xff", 5);
252 memset(buf, 0xff, sizeof(buf));
253 _mbsnbcpy(buf, mbsonlylead, 5);
254 expect_bin(buf, "\0\0\0\0\0\xff", 6);
256 /* _mbsinc/mbsdec */
257 step = _mbsinc(mbstring) - mbstring;
258 ok(step == 2, "_mbsinc adds %d (exp. 2)\n", step);
259 step = _mbsinc(&mbstring[2]) - &mbstring[2]; /* lead + invalid tail */
260 ok(step == 2, "_mbsinc adds %d (exp. 2)\n", step);
262 step = _mbsninc(mbsonlylead, 1) - mbsonlylead;
263 ok(step == 0, "_mbsninc adds %d (exp. 0)\n", step);
264 step = _mbsninc(mbsonlylead, 2) - mbsonlylead; /* lead + NUL byte + lead + char */
265 ok(step == 0, "_mbsninc adds %d (exp. 0)\n", step);
266 step = _mbsninc(mbstring2, 0) - mbstring2;
267 ok(step == 0, "_mbsninc adds %d (exp. 2)\n", step);
268 step = _mbsninc(mbstring2, 1) - mbstring2;
269 ok(step == 2, "_mbsninc adds %d (exp. 2)\n", step);
270 step = _mbsninc(mbstring2, 2) - mbstring2;
271 ok(step == 4, "_mbsninc adds %d (exp. 4)\n", step);
272 step = _mbsninc(mbstring2, 3) - mbstring2;
273 ok(step == 5, "_mbsninc adds %d (exp. 5)\n", step);
274 step = _mbsninc(mbstring2, 4) - mbstring2;
275 ok(step == 7, "_mbsninc adds %d (exp. 7)\n", step);
276 step = _mbsninc(mbstring2, 5) - mbstring2;
277 ok(step == 7, "_mbsninc adds %d (exp. 7)\n", step);
278 step = _mbsninc(mbstring2, 17) - mbstring2;
279 ok(step == 7, "_mbsninc adds %d (exp. 7)\n", step);
281 /* functions that depend on locale codepage, not mbcp.
282 * we hope the current locale to be SBCS because setlocale(LC_ALL, ".1252") seems not to work yet
283 * (as of Wine 0.9.43)
285 if (__mb_cur_max == 1)
287 expect_eq(mblen((char *)mbstring, 3), 1, int, "%x");
288 expect_eq(_mbstrlen((char *)mbstring2), 7, int, "%d");
290 else
291 skip("Current locale has double-byte charset - could leave to false positives\n");
293 _setmbcp(curr_mbcp);
296 static void test_mbsspn( void)
298 unsigned char str1[]="cabernet";
299 unsigned char str2[]="shiraz";
300 unsigned char set[]="abc";
301 unsigned char empty[]="";
302 int ret;
303 ret=_mbsspn( str1, set);
304 ok( ret==3, "_mbsspn returns %d should be 3\n", ret);
305 ret=_mbsspn( str2, set);
306 ok( ret==0, "_mbsspn returns %d should be 0\n", ret);
307 ret=_mbsspn( str1, empty);
308 ok( ret==0, "_mbsspn returns %d should be 0\n", ret);
311 static void test_mbsspnp( void)
313 unsigned char str1[]="cabernet";
314 unsigned char str2[]="shiraz";
315 unsigned char set[]="abc";
316 unsigned char empty[]="";
317 unsigned char full[]="abcenrt";
318 unsigned char* ret;
319 ret=_mbsspnp( str1, set);
320 ok( ret[0]=='e', "_mbsspnp returns %c should be e\n", ret[0]);
321 ret=_mbsspnp( str2, set);
322 ok( ret[0]=='s', "_mbsspnp returns %c should be s\n", ret[0]);
323 ret=_mbsspnp( str1, empty);
324 ok( ret[0]=='c', "_mbsspnp returns %c should be c\n", ret[0]);
325 ret=_mbsspnp( str1, full);
326 ok( ret==NULL, "_mbsspnp returns %p should be NULL\n", ret);
329 static void test_strdup(void)
331 char *str;
332 str = _strdup( 0 );
333 ok( str == 0, "strdup returns %s should be 0\n", str);
334 free( str );
337 START_TEST(string)
339 void *mem;
340 static const char xilstring[]="c:/xilinx";
341 int nLen;
343 hMsvcrt = GetModuleHandleA("msvcrt.dll");
344 if (!hMsvcrt)
345 hMsvcrt = GetModuleHandleA("msvcrtd.dll");
346 ok(hMsvcrt != 0, "GetModuleHandleA failed\n");
347 SET(pmemcpy,"memcpy");
348 SET(pmemcmp,"memcmp");
350 /* MSVCRT memcpy behaves like memmove for overlapping moves,
351 MFC42 CString::Insert seems to rely on that behaviour */
352 mem = malloc(100);
353 ok(mem != NULL, "memory not allocated for size 0\n");
354 strcpy((char*)mem,xilstring);
355 nLen=strlen(xilstring);
356 pmemcpy((char*)mem+5, mem,nLen+1);
357 ok(pmemcmp((char*)mem+5,xilstring, nLen) == 0,
358 "Got result %s\n",(char*)mem+5);
360 /* Test _swab function */
361 test_swab();
363 /* Test ismbblead*/
364 test_mbcp();
365 /* test _mbsspn */
366 test_mbsspn();
367 test_mbsspnp();
368 /* test _strdup */
369 test_strdup();