7bd30fc790ac82c54b5e9789587dfe0a03b5cdb8
[reactos.git] / modules / rostests / winetests / shlwapi / string.c
1 /* Unit test suite for SHLWAPI string functions
2 *
3 * Copyright 2003 Jon Griffiths
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #define WIN32_NO_STATUS
21 #define _INC_WINDOWS
22 #define COM_NO_WINDOWS_H
23
24 //#include <stdio.h>
25
26 #include <wine/test.h>
27 //#include "winbase.h"
28 //#include "winerror.h"
29 #include <winnls.h>
30 #include <ole2.h>
31 #define NO_SHLWAPI_REG
32 #define NO_SHLWAPI_PATH
33 #define NO_SHLWAPI_GDI
34 #define NO_SHLWAPI_STREAM
35 #include <shlwapi.h>
36 //#include "shtypes.h"
37
38 #define expect_eq(expr, val, type, fmt) do { \
39 type ret = expr; \
40 ok(ret == val, "Unexpected value of '" #expr "': " #fmt " instead of " #val "\n", ret); \
41 } while (0);
42
43 #define expect_eq2(expr, val1, val2, type, fmt) do { \
44 type ret = expr; \
45 ok(ret == val1 || ret == val2, "Unexpected value of '" #expr "': " #fmt " instead of " #val1 " or " #val2 "\n", ret); \
46 } while (0);
47
48 static BOOL (WINAPI *pChrCmpIA)(CHAR, CHAR);
49 static BOOL (WINAPI *pChrCmpIW)(WCHAR, WCHAR);
50 static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int);
51 static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int);
52 static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int);
53 static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int);
54 static LPSTR (WINAPI *pStrCatBuffA)(LPSTR,LPCSTR,INT);
55 static LPWSTR (WINAPI *pStrCatBuffW)(LPWSTR,LPCWSTR,INT);
56 static DWORD (WINAPI *pStrCatChainW)(LPWSTR,DWORD,DWORD,LPCWSTR);
57 static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int);
58 static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int);
59 static LPSTR (WINAPI *pStrFormatByteSize64A)(LONGLONG,LPSTR,UINT);
60 static LPSTR (WINAPI *pStrFormatKBSizeA)(LONGLONG,LPSTR,UINT);
61 static LPWSTR (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT);
62 static BOOL (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int);
63 static BOOL (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int);
64 static LPWSTR (WINAPI *pStrPBrkW)(LPCWSTR,LPCWSTR);
65 static LPSTR (WINAPI *pStrRChrA)(LPCSTR,LPCSTR,WORD);
66 static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,LPCITEMIDLIST,BSTR*);
67 static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT);
68 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
69 static LPWSTR (WINAPI *pStrStrNW)(LPCWSTR,LPCWSTR,UINT);
70 static LPWSTR (WINAPI *pStrStrNIW)(LPCWSTR,LPCWSTR,UINT);
71 static INT (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...);
72 static INT (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...);
73 static LPWSTR (WINAPI *pStrChrNW)(LPCWSTR,WCHAR,UINT);
74 static BOOL (WINAPI *pStrToInt64ExA)(LPCSTR,DWORD,LONGLONG*);
75 static BOOL (WINAPI *pStrToInt64ExW)(LPCWSTR,DWORD,LONGLONG*);
76
77 static int strcmpW(const WCHAR *str1, const WCHAR *str2)
78 {
79 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
80 return *str1 - *str2;
81 }
82
83 /* StrToInt/StrToIntEx results */
84 typedef struct tagStrToIntResult
85 {
86 const char* string;
87 int str_to_int;
88 LONGLONG str_to_int64_ex;
89 LONGLONG str_to_int64_hex;
90 } StrToIntResult;
91
92 static const StrToIntResult StrToInt_results[] = {
93 { "1099", 1099, 1099, 1099 },
94 { "4294967319", 23, ((LONGLONG)1 << 32) | 23, ((LONGLONG)1 << 32) | 23 },
95 { "+88987", 0, 88987, 88987 },
96 { "012", 12, 12, 12 },
97 { "-55", -55, -55, -55 },
98 { "-0", 0, 0, 0 },
99 { "0x44ff", 0, 0, 0x44ff },
100 { "0x2bdc546291f4b1", 0, 0, ((LONGLONG)0x2bdc54 << 32) | 0x6291f4b1 },
101 { "+0x44f4", 0, 0, 0x44f4 },
102 { "-0x44fd", 0, 0, 0x44fd },
103 { "+ 88987", 0, 0, 0 },
104 { "- 55", 0, 0, 0 },
105 { "- 0", 0, 0, 0 },
106 { "+ 0x44f4", 0, 0, 0 },
107 { "--0x44fd", 0, 0, 0 },
108 { " 1999", 0, 1999, 1999 },
109 { " +88987", 0, 88987, 88987 },
110 { " 012", 0, 12, 12 },
111 { " -55", 0, -55, -55 },
112 { " 0x44ff", 0, 0, 0x44ff },
113 { " +0x44f4", 0, 0, 0x44f4 },
114 { " -0x44fd", 0, 0, 0x44fd },
115 { NULL, 0, 0, 0 }
116 };
117
118 /* pStrFormatByteSize64/StrFormatKBSize results */
119 typedef struct tagStrFormatSizeResult
120 {
121 LONGLONG value;
122 const char* byte_size_64;
123 const char* kb_size;
124 int kb_size_broken;
125 const char* kb_size2;
126 } StrFormatSizeResult;
127
128
129 static const StrFormatSizeResult StrFormatSize_results[] = {
130 { -1023, "-1023 bytes", "0 KB"},
131 { -24, "-24 bytes", "0 KB"},
132 { 309, "309 bytes", "1 KB"},
133 { 10191, "9.95 KB", "10 KB"},
134 { 100353, "98.0 KB", "99 KB"},
135 { 1022286, "998 KB", "999 KB"},
136 { 1046862, "0.99 MB", "1,023 KB", 1, "1023 KB"},
137 { 1048574619, "999 MB", "1,023,999 KB", 1, "1023999 KB"},
138 { 1073741775, "0.99 GB", "1,048,576 KB", 1, "1048576 KB"},
139 { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB", 1, "1048575999 KB"},
140 { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB", 1, "1073741823 KB"},
141 { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB", 1, "4294967295 KB"},
142 { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB", 1, "4294967295 KB"},
143 { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB", 1, "0 KB"},
144 { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB", 1, "4294967295 KB"},
145 { 0, NULL, NULL }
146 };
147
148 /* StrFromTimeIntervalA/StrFromTimeIntervalW results */
149 typedef struct tagStrFromTimeIntervalResult
150 {
151 DWORD ms;
152 int digits;
153 const char* time_interval;
154 } StrFromTimeIntervalResult;
155
156
157 static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
158 { 1, 1, " 0 sec" },
159 { 1, 2, " 0 sec" },
160 { 1, 3, " 0 sec" },
161 { 1, 4, " 0 sec" },
162 { 1, 5, " 0 sec" },
163 { 1, 6, " 0 sec" },
164 { 1, 7, " 0 sec" },
165
166 { 1000000, 1, " 10 min" },
167 { 1000000, 2, " 16 min" },
168 { 1000000, 3, " 16 min 40 sec" },
169 { 1000000, 4, " 16 min 40 sec" },
170 { 1000000, 5, " 16 min 40 sec" },
171 { 1000000, 6, " 16 min 40 sec" },
172 { 1000000, 7, " 16 min 40 sec" },
173
174 { 1999999, 1, " 30 min" },
175 { 1999999, 2, " 33 min" },
176 { 1999999, 3, " 33 min 20 sec" },
177 { 1999999, 4, " 33 min 20 sec" },
178 { 1999999, 5, " 33 min 20 sec" },
179 { 1999999, 6, " 33 min 20 sec" },
180 { 1999999, 7, " 33 min 20 sec" },
181
182 { 3999997, 1, " 1 hr" },
183 { 3999997, 2, " 1 hr 6 min" },
184 { 3999997, 3, " 1 hr 6 min 40 sec" },
185 { 3999997, 4, " 1 hr 6 min 40 sec" },
186 { 3999997, 5, " 1 hr 6 min 40 sec" },
187 { 3999997, 6, " 1 hr 6 min 40 sec" },
188 { 3999997, 7, " 1 hr 6 min 40 sec" },
189
190 { 149999851, 7, " 41 hr 40 min 0 sec" },
191 { 150999850, 1, " 40 hr" },
192 { 150999850, 2, " 41 hr" },
193 { 150999850, 3, " 41 hr 50 min" },
194 { 150999850, 4, " 41 hr 56 min" },
195 { 150999850, 5, " 41 hr 56 min 40 sec" },
196 { 150999850, 6, " 41 hr 56 min 40 sec" },
197 { 150999850, 7, " 41 hr 56 min 40 sec" },
198
199 { 493999507, 1, " 100 hr" },
200 { 493999507, 2, " 130 hr" },
201 { 493999507, 3, " 137 hr" },
202 { 493999507, 4, " 137 hr 10 min" },
203 { 493999507, 5, " 137 hr 13 min" },
204 { 493999507, 6, " 137 hr 13 min 20 sec" },
205 { 493999507, 7, " 137 hr 13 min 20 sec" },
206
207 { 0, 0, NULL }
208 };
209
210
211 /* Returns true if the user interface is in English. Note that this does not
212 * presume of the formatting of dates, numbers, etc.
213 */
214 static BOOL is_lang_english(void)
215 {
216 static HMODULE hkernel32 = NULL;
217 static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL;
218 static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL;
219
220 if (!hkernel32)
221 {
222 hkernel32 = GetModuleHandleA("kernel32.dll");
223 pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage");
224 pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage");
225 }
226 if (pGetThreadUILanguage)
227 return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH;
228 if (pGetUserDefaultUILanguage)
229 return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH;
230
231 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
232 }
233
234 /* Returns true if the dates, numbers, etc. are formatted using English
235 * conventions.
236 */
237 static BOOL is_locale_english(void)
238 {
239 /* Surprisingly GetThreadLocale() is irrelevant here */
240 return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
241 }
242
243 static void test_StrChrA(void)
244 {
245 char string[129];
246 WORD count;
247
248 /* this test crashes on win2k SP4 */
249 /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
250
251 for (count = 32; count < 128; count++)
252 string[count] = (char)count;
253 string[128] = '\0';
254
255 for (count = 32; count < 128; count++)
256 {
257 LPSTR result = StrChrA(string+32, count);
258 INT pos = result - string;
259 ok(pos == count, "found char '%c' in wrong place: got %d, expected %d\n", count, pos, count);
260 }
261
262 for (count = 32; count < 128; count++)
263 {
264 LPSTR result = StrChrA(string+count+1, count);
265 ok(!result, "found char '%c' not in the string\n", count);
266 }
267 }
268
269 static void test_StrChrW(void)
270 {
271 WCHAR string[16385];
272 WORD count;
273
274 /* this test crashes on win2k SP4 */
275 /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
276
277 for (count = 32; count < 16384; count++)
278 string[count] = count;
279 string[16384] = '\0';
280
281 for (count = 32; count < 16384; count++)
282 {
283 LPWSTR result = StrChrW(string+32, count);
284 ok((result - string) == count, "found char %d in wrong place\n", count);
285 }
286
287 for (count = 32; count < 16384; count++)
288 {
289 LPWSTR result = StrChrW(string+count+1, count);
290 ok(!result, "found char not in the string\n");
291 }
292 }
293
294 static void test_StrChrIA(void)
295 {
296 char string[129];
297 WORD count;
298
299 /* this test crashes on win2k SP4 */
300 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
301
302 for (count = 32; count < 128; count++)
303 string[count] = (char)count;
304 string[128] = '\0';
305
306 for (count = 'A'; count <= 'X'; count++)
307 {
308 LPSTR result = StrChrIA(string+32, count);
309
310 ok(result - string == count, "found char '%c' in wrong place\n", count);
311 ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
312 }
313
314 for (count = 'a'; count < 'z'; count++)
315 {
316 LPSTR result = StrChrIA(string+count+1, count);
317 ok(!result, "found char not in the string\n");
318 }
319 }
320
321 static void test_StrChrIW(void)
322 {
323 WCHAR string[129];
324 WORD count;
325
326 /* this test crashes on win2k SP4 */
327 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
328
329 for (count = 32; count < 128; count++)
330 string[count] = count;
331 string[128] = '\0';
332
333 for (count = 'A'; count <= 'X'; count++)
334 {
335 LPWSTR result = StrChrIW(string+32, count);
336
337 ok(result - string == count, "found char '%c' in wrong place\n", count);
338 ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
339 }
340
341 for (count = 'a'; count < 'z'; count++)
342 {
343 LPWSTR result = StrChrIW(string+count+1, count);
344 ok(!result, "found char not in the string\n");
345 }
346 }
347
348 static void test_StrRChrA(void)
349 {
350 char string[129];
351 WORD count;
352
353 /* this test crashes on win2k SP4 */
354 /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
355
356 for (count = 32; count < 128; count++)
357 string[count] = (char)count;
358 string[128] = '\0';
359
360 for (count = 32; count < 128; count++)
361 {
362 LPSTR result = StrRChrA(string+32, NULL, count);
363 ok(result - string == count, "found char %d in wrong place\n", count);
364 }
365
366 for (count = 32; count < 128; count++)
367 {
368 LPSTR result = StrRChrA(string+count+1, NULL, count);
369 ok(!result, "found char not in the string\n");
370 }
371
372 for (count = 32; count < 128; count++)
373 {
374 LPSTR result = StrRChrA(string+count+1, string + 127, count);
375 ok(!result, "found char not in the string\n");
376 }
377 }
378
379 static void test_StrRChrW(void)
380 {
381 WCHAR string[129];
382 WORD count;
383
384 /* this test crashes on win2k SP4 */
385 /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
386
387 for (count = 32; count < 128; count++)
388 string[count] = count;
389 string[128] = '\0';
390
391 for (count = 32; count < 128; count++)
392 {
393 LPWSTR result = StrRChrW(string+32, NULL, count);
394 INT pos = result - string;
395 ok(pos == count, "found char %d in wrong place: got %d, expected %d\n", count, pos, count);
396 }
397
398 for (count = 32; count < 128; count++)
399 {
400 LPWSTR result = StrRChrW(string+count+1, NULL, count);
401 ok(!result, "found char %d not in the string\n", count);
402 }
403
404 for (count = 32; count < 128; count++)
405 {
406 LPWSTR result = StrRChrW(string+count+1, string + 127, count);
407 ok(!result, "found char %d not in the string\n", count);
408 }
409 }
410
411 static void test_StrCpyW(void)
412 {
413 WCHAR szSrc[256];
414 WCHAR szBuff[256];
415 const StrFormatSizeResult* result = StrFormatSize_results;
416 LPWSTR lpRes;
417
418 while(result->value)
419 {
420 MultiByteToWideChar(CP_ACP,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
421
422 lpRes = StrCpyW(szBuff, szSrc);
423 ok(!StrCmpW(szSrc, szBuff) && lpRes == szBuff, "Copied string %s wrong\n", result->byte_size_64);
424 result++;
425 }
426
427 /* this test crashes on win2k SP4 */
428 /*lpRes = StrCpyW(szBuff, NULL);*/
429 /*ok(lpRes == szBuff, "Wrong return value: got %p expected %p\n", lpRes, szBuff);*/
430
431 /* this test crashes on win2k SP4 */
432 /*lpRes = StrCpyW(NULL, szSrc);*/
433 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
434
435 /* this test crashes on win2k SP4 */
436 /*lpRes = StrCpyW(NULL, NULL);*/
437 /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
438 }
439
440 static void test_StrChrNW(void)
441 {
442 static const WCHAR string[] = {'T','e','s','t','i','n','g',' ','S','t','r','i','n','g',0};
443 LPWSTR p;
444
445 if (!pStrChrNW)
446 {
447 win_skip("StrChrNW not available\n");
448 return;
449 }
450
451 p = pStrChrNW(string,'t',10);
452 ok(*p=='t',"Found wrong 't'\n");
453 ok(*(p+1)=='i',"next should be 'i'\n");
454
455 p = pStrChrNW(string,'S',10);
456 ok(*p=='S',"Found wrong 'S'\n");
457
458 p = pStrChrNW(string,'r',10);
459 ok(p==NULL,"Should not have found 'r'\n");
460 }
461
462 static void test_StrToIntA(void)
463 {
464 const StrToIntResult *result = StrToInt_results;
465 int return_val;
466
467 while (result->string)
468 {
469 return_val = StrToIntA(result->string);
470 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
471 result->string, return_val);
472 result++;
473 }
474 }
475
476 static void test_StrToIntW(void)
477 {
478 WCHAR szBuff[256];
479 const StrToIntResult *result = StrToInt_results;
480 int return_val;
481
482 while (result->string)
483 {
484 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
485 return_val = StrToIntW(szBuff);
486 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
487 result->string, return_val);
488 result++;
489 }
490 }
491
492 static void test_StrToIntExA(void)
493 {
494 const StrToIntResult *result = StrToInt_results;
495 int return_val;
496 BOOL bRet;
497
498 while (result->string)
499 {
500 return_val = -1;
501 bRet = StrToIntExA(result->string,0,&return_val);
502 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
503 result->string);
504 if (bRet)
505 ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
506 result->string, return_val);
507 result++;
508 }
509
510 result = StrToInt_results;
511 while (result->string)
512 {
513 return_val = -1;
514 bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val);
515 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
516 result->string);
517 if (bRet)
518 ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
519 result->string, return_val);
520 result++;
521 }
522 }
523
524 static void test_StrToIntExW(void)
525 {
526 WCHAR szBuff[256];
527 const StrToIntResult *result = StrToInt_results;
528 int return_val;
529 BOOL bRet;
530
531 while (result->string)
532 {
533 return_val = -1;
534 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
535 bRet = StrToIntExW(szBuff, 0, &return_val);
536 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
537 result->string);
538 if (bRet)
539 ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
540 result->string, return_val);
541 result++;
542 }
543
544 result = StrToInt_results;
545 while (result->string)
546 {
547 return_val = -1;
548 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
549 bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val);
550 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
551 result->string);
552 if (bRet)
553 ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
554 result->string, return_val);
555 result++;
556 }
557 }
558
559 static void test_StrToInt64ExA(void)
560 {
561 const StrToIntResult *result = StrToInt_results;
562 LONGLONG return_val;
563 BOOL bRet;
564
565 if (!pStrToInt64ExA)
566 {
567 win_skip("StrToInt64ExA() is not available\n");
568 return;
569 }
570
571 while (result->string)
572 {
573 return_val = -1;
574 bRet = pStrToInt64ExA(result->string,0,&return_val);
575 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
576 result->string);
577 if (bRet)
578 ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%08x%08x)\n",
579 result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
580 result++;
581 }
582
583 result = StrToInt_results;
584 while (result->string)
585 {
586 return_val = -1;
587 bRet = pStrToInt64ExA(result->string,STIF_SUPPORT_HEX,&return_val);
588 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
589 result->string);
590 if (bRet)
591 ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%08x%08x)\n",
592 result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
593 result++;
594 }
595 }
596
597 static void test_StrToInt64ExW(void)
598 {
599 WCHAR szBuff[256];
600 const StrToIntResult *result = StrToInt_results;
601 LONGLONG return_val;
602 BOOL bRet;
603
604 if (!pStrToInt64ExW)
605 {
606 win_skip("StrToInt64ExW() is not available\n");
607 return;
608 }
609
610 while (result->string)
611 {
612 return_val = -1;
613 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
614 bRet = pStrToInt64ExW(szBuff, 0, &return_val);
615 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
616 result->string);
617 if (bRet)
618 ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%08x%08x)\n",
619 result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
620 result++;
621 }
622
623 result = StrToInt_results;
624 while (result->string)
625 {
626 return_val = -1;
627 MultiByteToWideChar(CP_ACP,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
628 bRet = pStrToInt64ExW(szBuff, STIF_SUPPORT_HEX, &return_val);
629 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
630 result->string);
631 if (bRet)
632 ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%08x%08x)\n",
633 result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
634 result++;
635 }
636 }
637
638 static void test_StrDupA(void)
639 {
640 LPSTR lpszStr;
641 const StrFormatSizeResult* result = StrFormatSize_results;
642
643 while(result->value)
644 {
645 lpszStr = StrDupA(result->byte_size_64);
646
647 ok(lpszStr != NULL, "Dup failed\n");
648 if (lpszStr)
649 {
650 ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n");
651 LocalFree(lpszStr);
652 }
653 result++;
654 }
655
656 /* Later versions of shlwapi return NULL for this, but earlier versions
657 * returned an empty string (as Wine does).
658 */
659 lpszStr = StrDupA(NULL);
660 ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
661 LocalFree(lpszStr);
662 }
663
664 static void test_StrFormatByteSize64A(void)
665 {
666 char szBuff[256];
667 const StrFormatSizeResult* result = StrFormatSize_results;
668
669 if (!pStrFormatByteSize64A)
670 {
671 win_skip("StrFormatByteSize64A() is not available\n");
672 return;
673 }
674
675 while(result->value)
676 {
677 pStrFormatByteSize64A(result->value, szBuff, 256);
678
679 ok(!strcmp(result->byte_size_64, szBuff),
680 "Formatted %x%08x wrong: got %s, expected %s\n",
681 (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64);
682
683 result++;
684 }
685 }
686
687 static void test_StrFormatKBSizeW(void)
688 {
689 WCHAR szBuffW[256];
690 char szBuff[256];
691 const StrFormatSizeResult* result = StrFormatSize_results;
692
693 if (!pStrFormatKBSizeW)
694 {
695 win_skip("StrFormatKBSizeW() is not available\n");
696 return;
697 }
698
699 while(result->value)
700 {
701 pStrFormatKBSizeW(result->value, szBuffW, 256);
702 WideCharToMultiByte(CP_ACP,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),NULL,NULL);
703
704 ok(!strcmp(result->kb_size, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n",
705 (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
706 result++;
707 }
708 }
709
710 static void test_StrFormatKBSizeA(void)
711 {
712 char szBuff[256];
713 const StrFormatSizeResult* result = StrFormatSize_results;
714
715 if (!pStrFormatKBSizeA)
716 {
717 win_skip("StrFormatKBSizeA() is not available\n");
718 return;
719 }
720
721 while(result->value)
722 {
723 pStrFormatKBSizeA(result->value, szBuff, 256);
724
725 /* shlwapi on Win98 SE does not appear to apply delimiters to the output
726 * and does not correctly handle extremely large values. */
727 ok(!strcmp(result->kb_size, szBuff) ||
728 (result->kb_size_broken && !strcmp(result->kb_size2, szBuff)),
729 "Formatted %x%08x wrong: got %s, expected %s\n",
730 (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
731 result++;
732 }
733 }
734
735 static void test_StrFromTimeIntervalA(void)
736 {
737 char szBuff[256];
738 const StrFromTimeIntervalResult* result = StrFromTimeInterval_results;
739
740 while(result->ms)
741 {
742 StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
743
744 ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong: %s\n",
745 result->ms, result->digits, szBuff);
746 result++;
747 }
748 }
749
750 static void test_StrCmpA(void)
751 {
752 static const char str1[] = {'a','b','c','d','e','f'};
753 static const char str2[] = {'a','B','c','d','e','f'};
754 ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n");
755 ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n");
756 if (pChrCmpIA) {
757 ok(!pChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
758 ok(!pChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
759 ok(pChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
760 }
761 else
762 win_skip("ChrCmpIA() is not available\n");
763
764 if (pStrIsIntlEqualA)
765 {
766 ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
767 ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
768 }
769 else
770 win_skip("StrIsIntlEqualA() is not available\n");
771
772 if (pIntlStrEqWorkerA)
773 {
774 ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
775 ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
776 }
777 else
778 win_skip("IntlStrEqWorkerA() is not available\n");
779 }
780
781 static void test_StrCmpW(void)
782 {
783 static const WCHAR str1[] = {'a','b','c','d','e','f'};
784 static const WCHAR str2[] = {'a','B','c','d','e','f'};
785 ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n");
786 ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n");
787 if (pChrCmpIW) {
788 ok(!pChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
789 ok(!pChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
790 ok(pChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
791 }
792 else
793 win_skip("ChrCmpIW() is not available\n");
794
795 if (pStrIsIntlEqualW)
796 {
797 ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
798 ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
799 }
800 else
801 win_skip("StrIsIntlEqualW() is not available\n");
802
803 if (pIntlStrEqWorkerW)
804 {
805 ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
806 ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
807 }
808 else
809 win_skip("IntlStrEqWorkerW() is not available\n");
810 }
811
812 static WCHAR *CoDupStrW(const char* src)
813 {
814 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
815 WCHAR* szTemp = CoTaskMemAlloc(len * sizeof(WCHAR));
816 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
817 return szTemp;
818 }
819
820 static void test_StrRetToBSTR(void)
821 {
822 static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
823 ITEMIDLIST iidl[10];
824 BSTR bstr;
825 STRRET strret;
826 HRESULT ret;
827
828 if (!pStrRetToBSTR)
829 {
830 win_skip("StrRetToBSTR() is not available\n");
831 return;
832 }
833
834 strret.uType = STRRET_WSTR;
835 U(strret).pOleStr = CoDupStrW("Test");
836 bstr = 0;
837 ret = pStrRetToBSTR(&strret, NULL, &bstr);
838 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
839 "STRRET_WSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
840 SysFreeString(bstr);
841
842 strret.uType = STRRET_CSTR;
843 lstrcpyA(U(strret).cStr, "Test");
844 ret = pStrRetToBSTR(&strret, NULL, &bstr);
845 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
846 "STRRET_CSTR: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
847 SysFreeString(bstr);
848
849 strret.uType = STRRET_OFFSET;
850 U(strret).uOffset = 1;
851 strcpy((char*)&iidl, " Test");
852 ret = pStrRetToBSTR(&strret, iidl, &bstr);
853 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
854 "STRRET_OFFSET: dup failed, ret=0x%08x, bstr %p\n", ret, bstr);
855 SysFreeString(bstr);
856
857 /* Native crashes if str is NULL */
858 }
859
860 static void test_StrCpyNXA(void)
861 {
862 LPCSTR lpSrc = "hello";
863 LPSTR lpszRes;
864 char dest[8];
865
866 if (!pStrCpyNXA)
867 {
868 win_skip("StrCpyNXA() is not available\n");
869 return;
870 }
871
872 memset(dest, '\n', sizeof(dest));
873 lpszRes = pStrCpyNXA(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
874 ok(lpszRes == dest + 5 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
875 "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
876 dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
877 }
878
879 static void test_StrCpyNXW(void)
880 {
881 static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
882 static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
883 static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
884 LPWSTR lpszRes;
885 WCHAR dest[8];
886
887 if (!pStrCpyNXW)
888 {
889 win_skip("StrCpyNXW() is not available\n");
890 return;
891 }
892
893 memcpy(dest, lpInit, sizeof(lpInit));
894 lpszRes = pStrCpyNXW(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
895 ok(lpszRes == dest + 5 && !memcmp(dest, lpRes, sizeof(dest)),
896 "StrCpyNXW: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
897 dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
898 }
899
900 #define check_strrstri(type, str, pos, needle, exp) \
901 ret##type = StrRStrI##type(str, str+pos, needle); \
902 ok(ret##type == (exp), "Type " #type ", expected %p but got %p (string base %p)\n", \
903 (exp), ret##type, str);
904
905 static void test_StrRStrI(void)
906 {
907 static const CHAR szTest[] = "yAxxxxAy";
908 static const CHAR szTest2[] = "ABABABAB";
909 static const WCHAR wszTest[] = {'y','A','x','x','x','x','A','y',0};
910 static const WCHAR wszTest2[] = {'A','B','A','B','A','B','A','B',0};
911
912 static const WCHAR wszPattern1[] = {'A',0};
913 static const WCHAR wszPattern2[] = {'a','X',0};
914 static const WCHAR wszPattern3[] = {'A','y',0};
915 static const WCHAR wszPattern4[] = {'a','b',0};
916 LPWSTR retW;
917 LPSTR retA;
918
919 check_strrstri(A, szTest, 4, "A", szTest+1);
920 check_strrstri(A, szTest, 4, "aX", szTest+1);
921 check_strrstri(A, szTest, 4, "Ay", NULL);
922 check_strrstri(W, wszTest, 4, wszPattern1, wszTest+1);
923 check_strrstri(W, wszTest, 4, wszPattern2, wszTest+1);
924 check_strrstri(W, wszTest, 4, wszPattern3, NULL);
925
926 check_strrstri(A, szTest2, 4, "ab", szTest2+2);
927 check_strrstri(A, szTest2, 3, "ab", szTest2+2);
928 check_strrstri(A, szTest2, 2, "ab", szTest2);
929 check_strrstri(A, szTest2, 1, "ab", szTest2);
930 check_strrstri(A, szTest2, 0, "ab", NULL);
931 check_strrstri(W, wszTest2, 4, wszPattern4, wszTest2+2);
932 check_strrstri(W, wszTest2, 3, wszPattern4, wszTest2+2);
933 check_strrstri(W, wszTest2, 2, wszPattern4, wszTest2);
934 check_strrstri(W, wszTest2, 1, wszPattern4, wszTest2);
935 check_strrstri(W, wszTest2, 0, wszPattern4, NULL);
936
937 }
938
939 static void test_SHAnsiToAnsi(void)
940 {
941 char dest[8];
942 DWORD dwRet;
943
944 if (!pSHAnsiToAnsi)
945 {
946 win_skip("SHAnsiToAnsi() is not available\n");
947 return;
948 }
949
950 if (pSHAnsiToAnsi == (void *)pStrPBrkW)
951 {
952 win_skip("Ordinal 345 corresponds to StrPBrkW, skipping SHAnsiToAnsi tests\n");
953 return;
954 }
955
956 memset(dest, '\n', sizeof(dest));
957 dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0]));
958 ok(dwRet == 6 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
959 "SHAnsiToAnsi: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
960 dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
961 }
962
963 static void test_SHUnicodeToUnicode(void)
964 {
965 static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
966 static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
967 static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
968 WCHAR dest[8];
969 DWORD dwRet;
970
971 if (!pSHUnicodeToUnicode)
972 {
973 win_skip("SHUnicodeToUnicode() is not available\n");
974 return;
975 }
976
977 if (pSHUnicodeToUnicode == (void *)pStrRChrA)
978 {
979 win_skip("Ordinal 346 corresponds to StrRChrA, skipping SHUnicodeToUnicode tests\n");
980 return;
981 }
982
983 memcpy(dest, lpInit, sizeof(lpInit));
984 dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0]));
985 ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)),
986 "SHUnicodeToUnicode: expected 6, \"hello\\0\\n\\n\", got %d, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
987 dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
988 }
989
990 static void test_StrXXX_overflows(void)
991 {
992 CHAR str1[2*MAX_PATH+1], buf[2*MAX_PATH];
993 WCHAR wstr1[2*MAX_PATH+1], wbuf[2*MAX_PATH];
994 const WCHAR fmt[] = {'%','s',0};
995 STRRET strret;
996 HRESULT hres;
997 int ret;
998 int i;
999
1000 for (i=0; i<2*MAX_PATH; i++)
1001 {
1002 str1[i] = '0'+(i%10);
1003 wstr1[i] = '0'+(i%10);
1004 }
1005 str1[2*MAX_PATH] = 0;
1006 wstr1[2*MAX_PATH] = 0;
1007
1008 memset(buf, 0xbf, sizeof(buf));
1009 expect_eq(StrCpyNA(buf, str1, 10), buf, PCHAR, "%p");
1010 expect_eq(buf[9], 0, CHAR, "%x");
1011 expect_eq(buf[10], '\xbf', CHAR, "%x");
1012
1013 if (pStrCatBuffA)
1014 {
1015 expect_eq(pStrCatBuffA(buf, str1, 100), buf, PCHAR, "%p");
1016 expect_eq(buf[99], 0, CHAR, "%x");
1017 expect_eq(buf[100], '\xbf', CHAR, "%x");
1018 }
1019 else
1020 win_skip("StrCatBuffA() is not available\n");
1021
1022 if (0)
1023 {
1024 /* crashes on XP */
1025 StrCpyNW(wbuf, (LPCWSTR)0x1, 10);
1026 StrCpyNW((LPWSTR)0x1, wstr1, 10);
1027 }
1028
1029 memset(wbuf, 0xbf, sizeof(wbuf));
1030 expect_eq(StrCpyNW(wbuf, (LPCWSTR)0x1, 1), wbuf, PWCHAR, "%p");
1031 expect_eq(wbuf[0], 0, WCHAR, "%x");
1032 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1033
1034 memset(wbuf, 0xbf, sizeof(wbuf));
1035 expect_eq(StrCpyNW(wbuf, 0, 10), wbuf, PWCHAR, "%p");
1036 expect_eq(wbuf[0], 0, WCHAR, "%x");
1037 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1038
1039 memset(wbuf, 0xbf, sizeof(wbuf));
1040 expect_eq(StrCpyNW(wbuf, 0, 0), wbuf, PWCHAR, "%p");
1041 expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
1042 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1043
1044 memset(wbuf, 0xbf, sizeof(wbuf));
1045 expect_eq(StrCpyNW(wbuf, wstr1, 0), wbuf, PWCHAR, "%p");
1046 expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
1047 expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
1048
1049 memset(wbuf, 0xbf, sizeof(wbuf));
1050 expect_eq(StrCpyNW(wbuf, wstr1, 10), wbuf, PWCHAR, "%p");
1051 expect_eq(wbuf[9], 0, WCHAR, "%x");
1052 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1053
1054 if (pStrCatBuffW)
1055 {
1056 expect_eq(pStrCatBuffW(wbuf, wstr1, 100), wbuf, PWCHAR, "%p");
1057 expect_eq(wbuf[99], 0, WCHAR, "%x");
1058 expect_eq(wbuf[100], (WCHAR)0xbfbf, WCHAR, "%x");
1059 }
1060 else
1061 win_skip("StrCatBuffW() is not available\n");
1062
1063 if (pStrRetToBufW)
1064 {
1065 memset(wbuf, 0xbf, sizeof(wbuf));
1066 strret.uType = STRRET_WSTR;
1067 U(strret).pOleStr = StrDupW(wstr1);
1068 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1069 ok(hres == E_NOT_SUFFICIENT_BUFFER || broken(hres == S_OK) /* winxp */,
1070 "StrRetToBufW returned %08x\n", hres);
1071 if (hres == E_NOT_SUFFICIENT_BUFFER)
1072 expect_eq(wbuf[0], 0, WCHAR, "%x");
1073 expect_eq(wbuf[9], 0, WCHAR, "%x");
1074 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1075
1076 memset(wbuf, 0xbf, sizeof(wbuf));
1077 strret.uType = STRRET_CSTR;
1078 StrCpyNA(U(strret).cStr, str1, MAX_PATH);
1079 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1080 ok(hres == S_OK, "StrRetToBufW returned %08x\n", hres);
1081 ok(!memcmp(wbuf, wstr1, 9*sizeof(WCHAR)) && !wbuf[9], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf));
1082
1083 memset(wbuf, 0xbf, sizeof(wbuf));
1084 strret.uType = STRRET_WSTR;
1085 U(strret).pOleStr = NULL;
1086 hres = pStrRetToBufW(&strret, NULL, wbuf, 10);
1087 ok(hres == E_FAIL, "StrRetToBufW returned %08x\n", hres);
1088 ok(!wbuf[0], "StrRetToBuf returned %s\n", wine_dbgstr_w(wbuf));
1089 }
1090 else
1091 win_skip("StrRetToBufW() is not available\n");
1092
1093 if (pStrRetToBufA)
1094 {
1095 memset(buf, 0xbf, sizeof(buf));
1096 strret.uType = STRRET_CSTR;
1097 StrCpyNA(U(strret).cStr, str1, MAX_PATH);
1098 expect_eq2(pStrRetToBufA(&strret, NULL, buf, 10), S_OK, E_NOT_SUFFICIENT_BUFFER /* Vista */, HRESULT, "%x");
1099 expect_eq(buf[9], 0, CHAR, "%x");
1100 expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
1101 }
1102 else
1103 win_skip("StrRetToBufA() is not available\n");
1104
1105 if (pwnsprintfA)
1106 {
1107 memset(buf, 0xbf, sizeof(buf));
1108 ret = pwnsprintfA(buf, 10, "%s", str1);
1109 ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret);
1110 expect_eq(buf[9], 0, CHAR, "%x");
1111 expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
1112 }
1113 else
1114 win_skip("wnsprintfA() is not available\n");
1115
1116 if (pwnsprintfW)
1117 {
1118 memset(wbuf, 0xbf, sizeof(wbuf));
1119 ret = pwnsprintfW(wbuf, 10, fmt, wstr1);
1120 ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret);
1121 expect_eq(wbuf[9], 0, WCHAR, "%x");
1122 expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
1123 }
1124 else
1125 win_skip("wnsprintfW() is not available\n");
1126 }
1127
1128 static void test_StrStrA(void)
1129 {
1130 static const char *deadbeefA = "DeAdBeEf";
1131
1132 const struct
1133 {
1134 const char *search;
1135 const char *expect;
1136 } StrStrA_cases[] =
1137 {
1138 {"", NULL},
1139 {"DeAd", deadbeefA},
1140 {"dead", NULL},
1141 {"AdBe", deadbeefA + 2},
1142 {"adbe", NULL},
1143 {"BeEf", deadbeefA + 4},
1144 {"beef", NULL},
1145 };
1146
1147 LPSTR ret;
1148 int i;
1149
1150 /* Tests crash on Win2k */
1151 if (0)
1152 {
1153 ret = StrStrA(NULL, NULL);
1154 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1155
1156 ret = StrStrA(NULL, "");
1157 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1158
1159 ret = StrStrA("", NULL);
1160 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1161 }
1162
1163 ret = StrStrA("", "");
1164 ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
1165
1166 for (i = 0; i < sizeof(StrStrA_cases)/sizeof(StrStrA_cases[0]); i++)
1167 {
1168 ret = StrStrA(deadbeefA, StrStrA_cases[i].search);
1169 ok(ret == StrStrA_cases[i].expect,
1170 "[%d] Expected StrStrA to return %p, got %p\n",
1171 i, StrStrA_cases[i].expect, ret);
1172 }
1173 }
1174
1175 static void test_StrStrW(void)
1176 {
1177 static const WCHAR emptyW[] = {0};
1178 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1179 static const WCHAR deadW[] = {'D','e','A','d',0};
1180 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1181 static const WCHAR adbeW[] = {'A','d','B','e',0};
1182 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1183 static const WCHAR beefW[] = {'B','e','E','f',0};
1184 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1185
1186 const struct
1187 {
1188 const WCHAR *search;
1189 const WCHAR *expect;
1190 } StrStrW_cases[] =
1191 {
1192 {emptyW, NULL},
1193 {deadW, deadbeefW},
1194 {dead_lowerW, NULL},
1195 {adbeW, deadbeefW + 2},
1196 {adbe_lowerW, NULL},
1197 {beefW, deadbeefW + 4},
1198 {beef_lowerW, NULL},
1199 };
1200
1201 LPWSTR ret;
1202 int i;
1203
1204 /* Tests crash on Win2k */
1205 if (0)
1206 {
1207 ret = StrStrW(NULL, NULL);
1208 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1209
1210 ret = StrStrW(NULL, emptyW);
1211 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1212
1213 ret = StrStrW(emptyW, NULL);
1214 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1215 }
1216
1217 ret = StrStrW(emptyW, emptyW);
1218 ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
1219
1220 for (i = 0; i < sizeof(StrStrW_cases)/sizeof(StrStrW_cases[0]); i++)
1221 {
1222 ret = StrStrW(deadbeefW, StrStrW_cases[i].search);
1223 ok(ret == StrStrW_cases[i].expect,
1224 "[%d] Expected StrStrW to return %p, got %p\n",
1225 i, StrStrW_cases[i].expect, ret);
1226 }
1227 }
1228
1229 static void test_StrStrIA(void)
1230 {
1231 static const char *deadbeefA = "DeAdBeEf";
1232
1233 const struct
1234 {
1235 const char *search;
1236 const char *expect;
1237 } StrStrIA_cases[] =
1238 {
1239 {"", NULL},
1240 {"DeAd", deadbeefA},
1241 {"dead", deadbeefA},
1242 {"AdBe", deadbeefA + 2},
1243 {"adbe", deadbeefA + 2},
1244 {"BeEf", deadbeefA + 4},
1245 {"beef", deadbeefA + 4},
1246 {"cafe", NULL},
1247 };
1248
1249 LPSTR ret;
1250 int i;
1251
1252 /* Tests crash on Win2k */
1253 if (0)
1254 {
1255 ret = StrStrIA(NULL, NULL);
1256 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1257
1258 ret = StrStrIA(NULL, "");
1259 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1260
1261 ret = StrStrIA("", NULL);
1262 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1263 }
1264
1265 ret = StrStrIA("", "");
1266 ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
1267
1268 for (i = 0; i < sizeof(StrStrIA_cases)/sizeof(StrStrIA_cases[0]); i++)
1269 {
1270 ret = StrStrIA(deadbeefA, StrStrIA_cases[i].search);
1271 ok(ret == StrStrIA_cases[i].expect,
1272 "[%d] Expected StrStrIA to return %p, got %p\n",
1273 i, StrStrIA_cases[i].expect, ret);
1274 }
1275 }
1276
1277 static void test_StrStrIW(void)
1278 {
1279 static const WCHAR emptyW[] = {0};
1280 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1281 static const WCHAR deadW[] = {'D','e','A','d',0};
1282 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1283 static const WCHAR adbeW[] = {'A','d','B','e',0};
1284 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1285 static const WCHAR beefW[] = {'B','e','E','f',0};
1286 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1287 static const WCHAR cafeW[] = {'c','a','f','e',0};
1288
1289 const struct
1290 {
1291 const WCHAR *search;
1292 const WCHAR *expect;
1293 } StrStrIW_cases[] =
1294 {
1295 {emptyW, NULL},
1296 {deadW, deadbeefW},
1297 {dead_lowerW, deadbeefW},
1298 {adbeW, deadbeefW + 2},
1299 {adbe_lowerW, deadbeefW + 2},
1300 {beefW, deadbeefW + 4},
1301 {beef_lowerW, deadbeefW + 4},
1302 {cafeW, NULL},
1303 };
1304
1305 LPWSTR ret;
1306 int i;
1307
1308 /* Tests crash on Win2k */
1309 if (0)
1310 {
1311 ret = StrStrIW(NULL, NULL);
1312 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1313
1314 ret = StrStrIW(NULL, emptyW);
1315 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1316
1317 ret = StrStrIW(emptyW, NULL);
1318 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1319 }
1320
1321 ret = StrStrIW(emptyW, emptyW);
1322 ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
1323
1324 for (i = 0; i < sizeof(StrStrIW_cases)/sizeof(StrStrIW_cases[0]); i++)
1325 {
1326 ret = StrStrIW(deadbeefW, StrStrIW_cases[i].search);
1327 ok(ret == StrStrIW_cases[i].expect,
1328 "[%d] Expected StrStrIW to return %p, got %p\n",
1329 i, StrStrIW_cases[i].expect, ret);
1330 }
1331 }
1332
1333 static void test_StrStrNW(void)
1334 {
1335 static const WCHAR emptyW[] = {0};
1336 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1337 static const WCHAR deadW[] = {'D','e','A','d',0};
1338 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1339 static const WCHAR adbeW[] = {'A','d','B','e',0};
1340 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1341 static const WCHAR beefW[] = {'B','e','E','f',0};
1342 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1343
1344 const struct
1345 {
1346 const WCHAR *search;
1347 const UINT count;
1348 const WCHAR *expect;
1349 } StrStrNW_cases[] =
1350 {
1351 {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1352 {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1353 {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1354 {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1355 {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1356 {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1357 {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1358 {beefW, 0, NULL},
1359 {beefW, 1, NULL},
1360 {beefW, 2, NULL},
1361 {beefW, 3, NULL},
1362 {beefW, 4, NULL},
1363 {beefW, 5, deadbeefW + 4},
1364 {beefW, 6, deadbeefW + 4},
1365 {beefW, 7, deadbeefW + 4},
1366 {beefW, 8, deadbeefW + 4},
1367 {beefW, 9, deadbeefW + 4},
1368 };
1369
1370 LPWSTR ret;
1371 UINT i;
1372
1373 if (!pStrStrNW)
1374 {
1375 win_skip("StrStrNW() is not available\n");
1376 return;
1377 }
1378
1379 ret = pStrStrNW(NULL, NULL, 0);
1380 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1381
1382 ret = pStrStrNW(NULL, NULL, 10);
1383 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1384
1385 ret = pStrStrNW(NULL, emptyW, 10);
1386 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1387
1388 ret = pStrStrNW(emptyW, NULL, 10);
1389 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1390
1391 ret = pStrStrNW(emptyW, emptyW, 10);
1392 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1393
1394 for (i = 0; i < sizeof(StrStrNW_cases)/sizeof(StrStrNW_cases[0]); i++)
1395 {
1396 ret = pStrStrNW(deadbeefW, StrStrNW_cases[i].search, StrStrNW_cases[i].count);
1397 ok(ret == StrStrNW_cases[i].expect,
1398 "[%d] Expected StrStrNW to return %p, got %p\n",
1399 i, StrStrNW_cases[i].expect, ret);
1400 }
1401
1402 /* StrStrNW accepts counts larger than the search string length but rejects
1403 * counts larger than around 2G. The limit seems to change based on the
1404 * caller executable itself. */
1405 ret = pStrStrNW(deadbeefW, beefW, 100);
1406 ok(ret == deadbeefW + 4, "Expected StrStrNW to return deadbeefW + 4, got %p\n", ret);
1407
1408 if (0)
1409 {
1410 ret = pStrStrNW(deadbeefW, beefW, ~0U);
1411 ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
1412 }
1413 }
1414
1415 static void test_StrStrNIW(void)
1416 {
1417 static const WCHAR emptyW[] = {0};
1418 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1419 static const WCHAR deadW[] = {'D','e','A','d',0};
1420 static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
1421 static const WCHAR adbeW[] = {'A','d','B','e',0};
1422 static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
1423 static const WCHAR beefW[] = {'B','e','E','f',0};
1424 static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
1425 static const WCHAR cafeW[] = {'c','a','f','e',0};
1426
1427 const struct
1428 {
1429 const WCHAR *search;
1430 const UINT count;
1431 const WCHAR *expect;
1432 } StrStrNIW_cases[] =
1433 {
1434 {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1435 {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1436 {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
1437 {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1438 {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
1439 {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1440 {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
1441 {cafeW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
1442 {beefW, 0, NULL},
1443 {beefW, 1, NULL},
1444 {beefW, 2, NULL},
1445 {beefW, 3, NULL},
1446 {beefW, 4, NULL},
1447 {beefW, 5, deadbeefW + 4},
1448 {beefW, 6, deadbeefW + 4},
1449 {beefW, 7, deadbeefW + 4},
1450 {beefW, 8, deadbeefW + 4},
1451 {beefW, 9, deadbeefW + 4},
1452 {beef_lowerW, 0, NULL},
1453 {beef_lowerW, 1, NULL},
1454 {beef_lowerW, 2, NULL},
1455 {beef_lowerW, 3, NULL},
1456 {beef_lowerW, 4, NULL},
1457 {beef_lowerW, 5, deadbeefW + 4},
1458 {beef_lowerW, 6, deadbeefW + 4},
1459 {beef_lowerW, 7, deadbeefW + 4},
1460 {beef_lowerW, 8, deadbeefW + 4},
1461 {beef_lowerW, 9, deadbeefW + 4},
1462 };
1463
1464 LPWSTR ret;
1465 UINT i;
1466
1467 if (!pStrStrNIW)
1468 {
1469 win_skip("StrStrNIW() is not available\n");
1470 return;
1471 }
1472
1473 ret = pStrStrNIW(NULL, NULL, 0);
1474 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1475
1476 ret = pStrStrNIW(NULL, NULL, 10);
1477 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1478
1479 ret = pStrStrNIW(NULL, emptyW, 10);
1480 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1481
1482 ret = pStrStrNIW(emptyW, NULL, 10);
1483 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1484
1485 ret = pStrStrNIW(emptyW, emptyW, 10);
1486 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1487
1488 for (i = 0; i < sizeof(StrStrNIW_cases)/sizeof(StrStrNIW_cases[0]); i++)
1489 {
1490 ret = pStrStrNIW(deadbeefW, StrStrNIW_cases[i].search, StrStrNIW_cases[i].count);
1491 ok(ret == StrStrNIW_cases[i].expect,
1492 "[%d] Expected StrStrNIW to return %p, got %p\n",
1493 i, StrStrNIW_cases[i].expect, ret);
1494 }
1495
1496 /* StrStrNIW accepts counts larger than the search string length but rejects
1497 * counts larger than around 2G. The limit seems to change based on the
1498 * caller executable itself. */
1499 ret = pStrStrNIW(deadbeefW, beefW, 100);
1500 ok(ret == deadbeefW + 4, "Expected StrStrNIW to return deadbeefW + 4, got %p\n", ret);
1501
1502 if (0)
1503 {
1504 ret = pStrStrNIW(deadbeefW, beefW, ~0U);
1505 ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
1506 }
1507 }
1508
1509 static void test_StrCatChainW(void)
1510 {
1511 static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
1512 static const WCHAR deadW[] = {'D','e','A','d',0};
1513 static const WCHAR beefW[] = {'B','e','E','f',0};
1514
1515 WCHAR buf[32 + 1];
1516 DWORD ret;
1517
1518 if (!pStrCatChainW)
1519 {
1520 win_skip("StrCatChainW is not available\n");
1521 return;
1522 }
1523
1524 /* Test with NULL buffer */
1525 ret = pStrCatChainW(NULL, 0, 0, beefW);
1526 ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
1527
1528 /* Test with empty buffer */
1529 memset(buf, 0x11, sizeof(buf));
1530 ret = pStrCatChainW(buf, 0, 0, beefW);
1531 ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
1532 ok(buf[0] == 0x1111, "Expected buf[0] = 0x1111, got %x\n", buf[0]);
1533
1534 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1535 ret = pStrCatChainW(buf, 0, -1, beefW);
1536 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1537 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1538
1539 /* Append data to existing string with offset = -1 */
1540 memset(buf, 0x11, sizeof(buf));
1541 ret = pStrCatChainW(buf, 32, 0, deadW);
1542 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1543 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1544
1545 ret = pStrCatChainW(buf, 32, -1, beefW);
1546 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1547 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1548
1549 /* Append data at a fixed offset */
1550 memset(buf, 0x11, sizeof(buf));
1551 ret = pStrCatChainW(buf, 32, 0, deadW);
1552 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1553 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1554
1555 ret = pStrCatChainW(buf, 32, 4, beefW);
1556 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1557 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1558
1559 /* Buffer exactly sufficient for string + terminating null */
1560 memset(buf, 0x11, sizeof(buf));
1561 ret = pStrCatChainW(buf, 5, 0, deadW);
1562 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1563 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1564
1565 /* Buffer too small, string will be truncated */
1566 memset(buf, 0x11, sizeof(buf));
1567 ret = pStrCatChainW(buf, 4, 0, deadW);
1568 if (ret == 4)
1569 {
1570 /* Windows 2000 and XP uses a slightly different implementation
1571 * for StrCatChainW, which doesn't ensure that strings are null-
1572 * terminated. Skip test if we detect such an implementation. */
1573 win_skip("Windows2000/XP behaviour detected for StrCatChainW, skipping tests\n");
1574 return;
1575 }
1576 ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
1577 ok(!memcmp(buf, deadW, 3 * sizeof(WCHAR)), "Buffer contains wrong data\n");
1578 ok(!buf[3], "String is not nullterminated\n");
1579 ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
1580
1581 /* Overwrite part of an existing string */
1582 ret = pStrCatChainW(buf, 4, 1, beefW);
1583 ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
1584 ok(buf[0] == 'D', "Expected buf[0] = 'D', got %x\n", buf[0]);
1585 ok(buf[1] == 'B', "Expected buf[1] = 'B', got %x\n", buf[1]);
1586 ok(buf[2] == 'e', "Expected buf[2] = 'e', got %x\n", buf[2]);
1587 ok(!buf[3], "String is not nullterminated\n");
1588 ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
1589
1590 /* Test appending to full buffer */
1591 memset(buf, 0x11, sizeof(buf));
1592 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1593 memcpy(buf + 9, deadW, sizeof(deadW));
1594 ret = pStrCatChainW(buf, 9, 8, beefW);
1595 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1596 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1597 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1598
1599 /* Offset points at the end of the buffer */
1600 ret = pStrCatChainW(buf, 9, 9, beefW);
1601 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1602 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1603 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1604
1605 /* Offset points outside of the buffer */
1606 ret = pStrCatChainW(buf, 9, 10, beefW);
1607 ok(ret == 10, "Expected StrCatChainW to return 10, got %u\n", ret);
1608 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1609 ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1610
1611 /* The same but without nullterminated string */
1612 memcpy(buf, deadbeefW, sizeof(deadbeefW));
1613 ret = pStrCatChainW(buf, 5, -1, deadW);
1614 ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
1615 ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
1616
1617 ret = pStrCatChainW(buf, 5, 5, deadW);
1618 ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
1619 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1620 ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
1621
1622 ret = pStrCatChainW(buf, 5, 6, deadW);
1623 ok(ret == 6, "Expected StrCatChainW to return 6, got %u\n", ret);
1624 ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
1625 ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
1626 }
1627
1628 START_TEST(string)
1629 {
1630 HMODULE hShlwapi;
1631 CHAR thousandDelim[8];
1632 CHAR decimalDelim[8];
1633 CoInitialize(0);
1634
1635 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousandDelim, 8);
1636 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimalDelim, 8);
1637
1638 hShlwapi = GetModuleHandleA("shlwapi");
1639 pChrCmpIA = (void *)GetProcAddress(hShlwapi, "ChrCmpIA");
1640 pChrCmpIW = (void *)GetProcAddress(hShlwapi, "ChrCmpIW");
1641 pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA");
1642 pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW");
1643 pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345);
1644 pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346);
1645 pStrCatBuffA = (void *)GetProcAddress(hShlwapi, "StrCatBuffA");
1646 pStrCatBuffW = (void *)GetProcAddress(hShlwapi, "StrCatBuffW");
1647 pStrCatChainW = (void *)GetProcAddress(hShlwapi, "StrCatChainW");
1648 pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399);
1649 pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400);
1650 pStrChrNW = (void *)GetProcAddress(hShlwapi, "StrChrNW");
1651 pStrFormatByteSize64A = (void *)GetProcAddress(hShlwapi, "StrFormatByteSize64A");
1652 pStrFormatKBSizeA = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeA");
1653 pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW");
1654 pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA");
1655 pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW");
1656 pStrPBrkW = (void *)GetProcAddress(hShlwapi, "StrPBrkW");
1657 pStrRChrA = (void *)GetProcAddress(hShlwapi, "StrRChrA");
1658 pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR");
1659 pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA");
1660 pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW");
1661 pStrStrNW = (void *)GetProcAddress(hShlwapi, "StrStrNW");
1662 pStrStrNIW = (void *)GetProcAddress(hShlwapi, "StrStrNIW");
1663 pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA");
1664 pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW");
1665 pStrToInt64ExA = (void *)GetProcAddress(hShlwapi, "StrToInt64ExA");
1666 pStrToInt64ExW = (void *)GetProcAddress(hShlwapi, "StrToInt64ExW");
1667
1668 test_StrChrA();
1669 test_StrChrW();
1670 test_StrChrIA();
1671 test_StrChrIW();
1672 test_StrRChrA();
1673 test_StrRChrW();
1674 test_StrCpyW();
1675 test_StrChrNW();
1676 test_StrToIntA();
1677 test_StrToIntW();
1678 test_StrToIntExA();
1679 test_StrToIntExW();
1680 test_StrToInt64ExA();
1681 test_StrToInt64ExW();
1682 test_StrDupA();
1683
1684 /* language-dependent test */
1685 if (is_lang_english() && is_locale_english())
1686 {
1687 test_StrFormatByteSize64A();
1688 test_StrFormatKBSizeA();
1689 test_StrFormatKBSizeW();
1690 }
1691 else
1692 skip("An English UI and locale is required for the StrFormat*Size tests\n");
1693 if (is_lang_english())
1694 test_StrFromTimeIntervalA();
1695 else
1696 skip("An English UI is required for the StrFromTimeInterval tests\n");
1697
1698 test_StrCmpA();
1699 test_StrCmpW();
1700 test_StrRetToBSTR();
1701 test_StrCpyNXA();
1702 test_StrCpyNXW();
1703 test_StrRStrI();
1704 test_SHAnsiToAnsi();
1705 test_SHUnicodeToUnicode();
1706 test_StrXXX_overflows();
1707 test_StrStrA();
1708 test_StrStrW();
1709 test_StrStrIA();
1710 test_StrStrIW();
1711 test_StrStrNW();
1712 test_StrStrNIW();
1713 test_StrCatChainW();
1714
1715 CoUninitialize();
1716 }