comctl32: A couple fixes for tab icon offsets.
[wine] / dlls / shlwapi / tests / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winnls.h"
28 #define NO_SHLWAPI_REG
29 #define NO_SHLWAPI_PATH
30 #define NO_SHLWAPI_GDI
31 #define NO_SHLWAPI_STREAM
32 #include "shlwapi.h"
33 #include "shtypes.h"
34
35 static HMODULE hShlwapi;
36 static LPSTR   (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int);
37 static LPWSTR  (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int);
38 static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*);
39 static DWORD   (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int);
40 static DWORD   (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int);
41 static BOOL    (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int);
42 static BOOL    (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int);
43 static BOOL    (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int);
44 static BOOL    (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int);
45
46 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
47 {
48     while (*str1 && (*str1 == *str2)) { str1++; str2++; }
49     return *str1 - *str2;
50 }
51
52 /* StrToInt/StrToIntEx results */
53 typedef struct tagStrToIntResult
54 {
55   const char* string;
56   int str_to_int;
57   int str_to_int_ex;
58   int str_to_int_hex;
59 } StrToIntResult;
60
61 static const StrToIntResult StrToInt_results[] = {
62      { "1099", 1099, 1099, 1099 },
63      { "+88987", 0, 88987, 88987 },
64      { "012", 12, 12, 12 },
65      { "-55", -55, -55, -55 },
66      { "-0", 0, 0, 0 },
67      { "0x44ff", 0, 0, 0x44ff },
68      { "+0x44f4", 0, 0, 0x44f4 },
69      { "-0x44fd", 0, 0, 0x44fd },
70      { "+ 88987", 0, 0, 0 },
71      { "- 55", 0, 0, 0 },
72      { "- 0", 0, 0, 0 },
73      { "+ 0x44f4", 0, 0, 0 },
74      { "--0x44fd", 0, 0, 0 },
75      { " 1999", 0, 1999, 1999 },
76      { " +88987", 0, 88987, 88987 },
77      { " 012", 0, 12, 12 },
78      { " -55", 0, -55, -55 },
79      { " 0x44ff", 0, 0, 0x44ff },
80      { " +0x44f4", 0, 0, 0x44f4 },
81      { " -0x44fd", 0, 0, 0x44fd },
82      { NULL, 0, 0, 0 }
83 };
84
85 /* pStrFormatByteSize64/StrFormatKBSize results */
86 typedef struct tagStrFormatSizeResult
87 {
88   LONGLONG value;
89   const char* byte_size_64;
90   const char* kb_size;
91 } StrFormatSizeResult;
92
93
94 static const StrFormatSizeResult StrFormatSize_results[] = {
95   { -1023, "-1023 bytes", "0 KB"},
96   { -24, "-24 bytes", "0 KB"},
97   { 309, "309 bytes", "1 KB"},
98   { 10191, "9.95 KB", "10 KB"},
99   { 100353, "98.0 KB", "99 KB"},
100   { 1022286, "998 KB", "999 KB"},
101   { 1046862, "0.99 MB", "1,023 KB"},
102   { 1048574619, "999 MB", "1,023,999 KB"},
103   { 1073741775, "0.99 GB", "1,048,576 KB"},
104   { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB"},
105   { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB"},
106   { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB"},
107   { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB"},
108   { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB"},
109   { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB"},
110   { 0, NULL, NULL }
111 };
112
113 /* StrFormatByteSize64/StrFormatKBSize results */
114 typedef struct tagStrFromTimeIntervalResult
115 {
116   DWORD ms;
117   int   digits;
118   const char* time_interval;
119 } StrFromTimeIntervalResult;
120
121
122 static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
123   { 1, 1, " 0 sec" },
124   { 1, 2, " 0 sec" },
125   { 1, 3, " 0 sec" },
126   { 1, 4, " 0 sec" },
127   { 1, 5, " 0 sec" },
128   { 1, 6, " 0 sec" },
129   { 1, 7, " 0 sec" },
130
131   { 1000000, 1, " 10 min" },
132   { 1000000, 2, " 16 min" },
133   { 1000000, 3, " 16 min 40 sec" },
134   { 1000000, 4, " 16 min 40 sec" },
135   { 1000000, 5, " 16 min 40 sec" },
136   { 1000000, 6, " 16 min 40 sec" },
137   { 1000000, 7, " 16 min 40 sec" },
138
139   { 1999999, 1, " 30 min" },
140   { 1999999, 2, " 33 min" },
141   { 1999999, 3, " 33 min 20 sec" },
142   { 1999999, 4, " 33 min 20 sec" },
143   { 1999999, 5, " 33 min 20 sec" },
144   { 1999999, 6, " 33 min 20 sec" },
145   { 1999999, 7, " 33 min 20 sec" },
146
147   { 3999997, 1, " 1 hr" },
148   { 3999997, 2, " 1 hr 6 min" },
149   { 3999997, 3, " 1 hr 6 min 40 sec" },
150   { 3999997, 4, " 1 hr 6 min 40 sec" },
151   { 3999997, 5, " 1 hr 6 min 40 sec" },
152   { 3999997, 6, " 1 hr 6 min 40 sec" },
153   { 3999997, 7, " 1 hr 6 min 40 sec" },
154
155   { 149999851, 7, " 41 hr 40 min 0 sec" },
156   { 150999850, 1, " 40 hr" },
157   { 150999850, 2, " 41 hr" },
158   { 150999850, 3, " 41 hr 50 min" },
159   { 150999850, 4, " 41 hr 56 min" },
160   { 150999850, 5, " 41 hr 56 min 40 sec" },
161   { 150999850, 6, " 41 hr 56 min 40 sec" },
162   { 150999850, 7, " 41 hr 56 min 40 sec" },
163
164   { 493999507, 1, " 100 hr" },
165   { 493999507, 2, " 130 hr" },
166   { 493999507, 3, " 137 hr" },
167   { 493999507, 4, " 137 hr 10 min" },
168   { 493999507, 5, " 137 hr 13 min" },
169   { 493999507, 6, " 137 hr 13 min 20 sec" },
170   { 493999507, 7, " 137 hr 13 min 20 sec" },
171
172   { 0, 0, NULL }
173 };
174
175 static void test_StrChrA(void)
176 {
177   char string[129];
178   WORD count;
179
180   /* this test crashes on win2k SP4 */
181   /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
182
183   for (count = 32; count < 128; count++)
184     string[count] = (char)count;
185   string[128] = '\0';
186
187   for (count = 32; count < 128; count++)
188   {
189     LPSTR result = StrChrA(string+32, count);
190     ok(result - string == count,
191         "found char '%c' in wrong place: got %d, expected %d\n",
192         count, result - string, count);
193   }
194
195   for (count = 32; count < 128; count++)
196   {
197     LPSTR result = StrChrA(string+count+1, count);
198     ok(!result, "found char '%c' not in the string\n", count);
199   }
200 }
201
202 static void test_StrChrW(void)
203 {
204   WCHAR string[16385];
205   WORD count;
206
207   /* this test crashes on win2k SP4 */
208   /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
209
210   for (count = 32; count < 16384; count++)
211     string[count] = count;
212   string[16384] = '\0';
213
214   for (count = 32; count < 16384; count++)
215   {
216     LPWSTR result = StrChrW(string+32, count);
217     ok((result - string) == count, "found char %d in wrong place\n", count);
218   }
219
220   for (count = 32; count < 16384; count++)
221   {
222     LPWSTR result = StrChrW(string+count+1, count);
223     ok(!result, "found char not in the string\n");
224   }
225 }
226
227 static void test_StrChrIA(void)
228 {
229   char string[129];
230   WORD count;
231
232   /* this test crashes on win2k SP4 */
233   /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
234
235   for (count = 32; count < 128; count++)
236     string[count] = (char)count;
237   string[128] = '\0';
238
239   for (count = 'A'; count <= 'X'; count++)
240   {
241     LPSTR result = StrChrIA(string+32, count);
242
243     ok(result - string == count, "found char '%c' in wrong place\n", count);
244     ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
245   }
246
247   for (count = 'a'; count < 'z'; count++)
248   {
249     LPSTR result = StrChrIA(string+count+1, count);
250     ok(!result, "found char not in the string\n");
251   }
252 }
253
254 static void test_StrChrIW(void)
255 {
256   WCHAR string[129];
257   WORD count;
258
259   /* this test crashes on win2k SP4 */
260   /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
261
262   for (count = 32; count < 128; count++)
263     string[count] = count;
264   string[128] = '\0';
265
266   for (count = 'A'; count <= 'X'; count++)
267   {
268     LPWSTR result = StrChrIW(string+32, count);
269
270     ok(result - string == count, "found char '%c' in wrong place\n", count);
271     ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
272   }
273
274   for (count = 'a'; count < 'z'; count++)
275   {
276     LPWSTR result = StrChrIW(string+count+1, count);
277     ok(!result, "found char not in the string\n");
278   }
279 }
280
281 static void test_StrRChrA(void)
282 {
283   char string[129];
284   WORD count;
285
286   /* this test crashes on win2k SP4 */
287   /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
288
289   for (count = 32; count < 128; count++)
290     string[count] = (char)count;
291   string[128] = '\0';
292
293   for (count = 32; count < 128; count++)
294   {
295     LPSTR result = StrRChrA(string+32, NULL, count);
296     ok(result - string == count, "found char %d in wrong place\n", count);
297   }
298
299   for (count = 32; count < 128; count++)
300   {
301     LPSTR result = StrRChrA(string+count+1, NULL, count);
302     ok(!result, "found char not in the string\n");
303   }
304
305   for (count = 32; count < 128; count++)
306   {
307     LPSTR result = StrRChrA(string+count+1, string + 127, count);
308     ok(!result, "found char not in the string\n");
309   }
310 }
311
312 static void test_StrRChrW(void)
313 {
314   WCHAR string[129];
315   WORD count;
316
317   /* this test crashes on win2k SP4 */
318   /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
319
320   for (count = 32; count < 128; count++)
321     string[count] = count;
322   string[128] = '\0';
323
324   for (count = 32; count < 128; count++)
325   {
326     LPWSTR result = StrRChrW(string+32, NULL, count);
327     ok(result - string == count,
328         "found char %d in wrong place: got %d, expected %d\n",
329         count, result - string, count);
330   }
331
332   for (count = 32; count < 128; count++)
333   {
334     LPWSTR result = StrRChrW(string+count+1, NULL, count);
335     ok(!result, "found char %d not in the string\n", count);
336   }
337
338   for (count = 32; count < 128; count++)
339   {
340     LPWSTR result = StrRChrW(string+count+1, string + 127, count);
341     ok(!result, "found char %d not in the string\n", count);
342   }
343 }
344
345 static void test_StrCpyW(void)
346 {
347   WCHAR szSrc[256];
348   WCHAR szBuff[256];
349   const StrFormatSizeResult* result = StrFormatSize_results;
350
351
352   while(result->value)
353   {
354     MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
355
356     StrCpyW(szBuff, szSrc);
357     ok(!StrCmpW(szSrc, szBuff), "Copied string %s wrong\n", result->byte_size_64);
358     result++;
359   }
360 }
361
362
363 static void test_StrToIntA(void)
364 {
365   const StrToIntResult *result = StrToInt_results;
366   int return_val;
367
368   while (result->string)
369   {
370     return_val = StrToIntA(result->string);
371     ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
372        result->string, return_val);
373     result++;
374   }
375 }
376
377 static void test_StrToIntW(void)
378 {
379   WCHAR szBuff[256];
380   const StrToIntResult *result = StrToInt_results;
381   int return_val;
382
383   while (result->string)
384   {
385     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
386     return_val = StrToIntW(szBuff);
387     ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
388        result->string, return_val);
389     result++;
390   }
391 }
392
393 static void test_StrToIntExA(void)
394 {
395   const StrToIntResult *result = StrToInt_results;
396   int return_val;
397   BOOL bRet;
398
399   while (result->string)
400   {
401     return_val = -1;
402     bRet = StrToIntExA(result->string,0,&return_val);
403     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
404        result->string);
405     if (bRet)
406       ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
407          result->string, return_val);
408     result++;
409   }
410
411   result = StrToInt_results;
412   while (result->string)
413   {
414     return_val = -1;
415     bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val);
416     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
417        result->string);
418     if (bRet)
419       ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
420          result->string, return_val);
421     result++;
422   }
423 }
424
425 static void test_StrToIntExW(void)
426 {
427   WCHAR szBuff[256];
428   const StrToIntResult *result = StrToInt_results;
429   int return_val;
430   BOOL bRet;
431
432   while (result->string)
433   {
434     return_val = -1;
435     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
436     bRet = StrToIntExW(szBuff, 0, &return_val);
437     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
438        result->string);
439     if (bRet)
440       ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
441          result->string, return_val);
442     result++;
443   }
444
445   result = StrToInt_results;
446   while (result->string)
447   {
448     return_val = -1;
449     MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
450     bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val);
451     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
452        result->string);
453     if (bRet)
454       ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
455          result->string, return_val);
456     result++;
457   }
458 }
459
460 static void test_StrDupA(void)
461 {
462   LPSTR lpszStr;
463   const StrFormatSizeResult* result = StrFormatSize_results;
464
465   while(result->value)
466   {
467     lpszStr = StrDupA(result->byte_size_64);
468
469     ok(lpszStr != NULL, "Dup failed\n");
470     if (lpszStr)
471     {
472       ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n");
473       LocalFree((HLOCAL)lpszStr);
474     }
475     result++;
476   }
477
478   /* Later versions of shlwapi return NULL for this, but earlier versions
479    * returned an empty string (as Wine does).
480    */
481   lpszStr = StrDupA(NULL);
482   ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
483 }
484
485 static void test_StrFormatByteSize64A(void)
486 {
487   char szBuff[256];
488   const StrFormatSizeResult* result = StrFormatSize_results;
489
490   while(result->value)
491   {
492     StrFormatByteSize64A(result->value, szBuff, 256);
493
494     ok(!strcmp(result->byte_size_64, szBuff),
495         "Formatted %lx%08lx wrong: got %s, expected %s\n",
496        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64);
497
498     result++;
499   }
500 }
501
502 static void test_StrFormatKBSizeW(void)
503 {
504   WCHAR szBuffW[256];
505   char szBuff[256];
506   const StrFormatSizeResult* result = StrFormatSize_results;
507
508   while(result->value)
509   {
510     StrFormatKBSizeW(result->value, szBuffW, 256);
511     WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
512     ok(!strcmp(result->kb_size, szBuff),
513         "Formatted %lx%08lx wrong: got %s, expected %s\n",
514        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
515     result++;
516   }
517 }
518
519 static void test_StrFormatKBSizeA(void)
520 {
521   char szBuff[256];
522   const StrFormatSizeResult* result = StrFormatSize_results;
523
524   while(result->value)
525   {
526     StrFormatKBSizeA(result->value, szBuff, 256);
527
528     ok(!strcmp(result->kb_size, szBuff),
529         "Formatted %lx%08lx wrong: got %s, expected %s\n",
530        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
531     result++;
532   }
533 }
534
535 static void test_StrFromTimeIntervalA(void)
536 {
537   char szBuff[256];
538   const StrFromTimeIntervalResult* result = StrFromTimeInterval_results;
539
540   while(result->ms)
541   {
542     StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
543
544     ok(!strcmp(result->time_interval, szBuff), "Formatted %ld %d wrong\n",
545        result->ms, result->digits);
546     result++;
547   }
548 }
549
550 static void test_StrCmpA(void)
551 {
552   static const char str1[] = {'a','b','c','d','e','f'};
553   static const char str2[] = {'a','B','c','d','e','f'};
554   ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n");
555   ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n");
556   ok(!ChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
557   ok(!ChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
558   ok(ChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
559
560   pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA");
561   pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA");
562
563   if (!pStrIsIntlEqualA)
564     return;
565
566   ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
567   ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
568
569   if (!pIntlStrEqWorkerA)
570     return;
571
572   ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
573   ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
574 }
575
576 static void test_StrCmpW(void)
577 {
578   static const WCHAR str1[] = {'a','b','c','d','e','f'};
579   static const WCHAR str2[] = {'a','B','c','d','e','f'};
580   ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n");
581   ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n");
582   ok(!ChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
583   ok(!ChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
584   ok(ChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
585
586   pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW");
587   pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW");
588
589   if (!pStrIsIntlEqualW)
590     return;
591
592   ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
593   ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
594
595   if (!pIntlStrEqWorkerW)
596     return;
597
598   ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
599   ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
600 }
601
602 static WCHAR *CoDupStrW(const char* src)
603 {
604   INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
605   WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR));
606   MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
607   return szTemp;
608 }
609
610 static void test_StrRetToBSTR(void)
611 {
612     static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
613     ITEMIDLIST iidl[10];
614     BSTR bstr;
615     STRRET strret;
616     HRESULT ret;
617
618     pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR");
619     if (!pStrRetToBSTR) return;
620
621     strret.uType = STRRET_WSTR;
622     strret.u.pOleStr = CoDupStrW("Test");
623     bstr = 0;
624     ret = pStrRetToBSTR(&strret, NULL, &bstr);
625     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
626        "STRRET_WSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
627     if (bstr)
628       SysFreeString(bstr);
629
630     strret.uType = STRRET_CSTR;
631     lstrcpyA(strret.u.cStr, "Test");
632     ret = pStrRetToBSTR(&strret, NULL, &bstr);
633     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
634        "STRRET_CSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
635     if (bstr)
636       SysFreeString(bstr);
637
638     strret.uType = STRRET_OFFSET;
639     strret.u.uOffset = 1;
640     strcpy((char*)&iidl, " Test");
641     ret = pStrRetToBSTR(&strret, iidl, &bstr);
642     ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
643        "STRRET_OFFSET: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
644     if (bstr)
645       SysFreeString(bstr);
646
647     /* Native crashes if str is NULL */
648 }
649
650 static void test_StrCpyNXA(void)
651 {
652   LPCSTR lpSrc = "hello";
653   LPSTR lpszRes;
654   char dest[8];
655
656   pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399);
657   if (!pStrCpyNXA)
658     return;
659
660   memset(dest, '\n', sizeof(dest));
661   lpszRes = pStrCpyNXA(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
662   ok(lpszRes == dest + 5 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
663        "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
664        dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
665 }
666
667 static void test_StrCpyNXW(void)
668 {
669   static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
670   static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
671   static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
672   LPWSTR lpszRes;
673   WCHAR dest[8];
674
675   pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400);
676   if (!pStrCpyNXW)
677     return;
678
679   memcpy(dest, lpInit, sizeof(lpInit));
680   lpszRes = pStrCpyNXW(dest, lpSrc, sizeof(dest)/sizeof(dest[0]));
681   ok(lpszRes == dest + 5 && !memcmp(dest, lpRes, sizeof(dest)),
682        "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
683        dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
684 }
685
686 static void test_SHAnsiToAnsi(void)
687 {
688   char dest[8];
689   DWORD dwRet;
690
691   pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345);
692   if (!pSHAnsiToAnsi)
693     return;
694
695   memset(dest, '\n', sizeof(dest));
696   dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0]));
697   ok(dwRet == 6 && !memcmp(dest, "hello\0\n\n", sizeof(dest)),
698      "SHAnsiToAnsi: expected 6, \"hello\\0\\n\\n\", got %ld, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
699      dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
700 }
701
702 static void test_SHUnicodeToUnicode(void)
703 {
704   static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' };
705   static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' };
706   static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' };
707   WCHAR dest[8];
708   DWORD dwRet;
709
710   pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346);
711   if (!pSHUnicodeToUnicode)
712     return;
713
714   memcpy(dest, lpInit, sizeof(lpInit));
715   dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0]));
716   ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)),
717      "SHUnicodeToUnicode: expected 6, \"hello\\0\\n\\n\", got %ld, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n",
718      dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
719 }
720
721 START_TEST(string)
722 {
723   CoInitialize(0);
724
725   hShlwapi = GetModuleHandleA("shlwapi");
726   if (!hShlwapi)
727      return;
728
729   test_StrChrA();
730   test_StrChrW();
731   test_StrChrIA();
732   test_StrChrIW();
733   test_StrRChrA();
734   test_StrRChrW();
735   test_StrCpyW();
736   test_StrToIntA();
737   test_StrToIntW();
738   test_StrToIntExA();
739   test_StrToIntExW();
740   test_StrDupA();
741   if (0)
742   {
743     /* this test fails on locales which do not use '.' as a decimal separator */
744     test_StrFormatByteSize64A();
745
746     /* this test fails on locales which do not use '.' as a decimal separator */
747     test_StrFormatKBSizeA();
748
749     /* FIXME: Awaiting NLS fixes in kernel before these succeed */
750     test_StrFormatKBSizeW();
751   }
752   test_StrFromTimeIntervalA();
753   test_StrCmpA();
754   test_StrCmpW();
755   test_StrRetToBSTR();
756   test_StrCpyNXA();
757   test_StrCpyNXW();
758   test_SHAnsiToAnsi();
759   test_SHUnicodeToUnicode();
760 }