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