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