1 /* Unit test suite for SHLWAPI string functions
3 * Copyright 2003 Jon Griffiths
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.
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.
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
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
25 #include "wine/test.h"
29 #define NO_SHLWAPI_REG
30 #define NO_SHLWAPI_PATH
31 #define NO_SHLWAPI_GDI
32 #define NO_SHLWAPI_STREAM
36 static HRESULT (WINAPI *ptr_StrRetToBSTR) (STRRET*, void*, BSTR*);
38 static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
40 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
44 /* StrToInt/StrToIntEx results */
45 typedef struct tagStrToIntResult
53 static const StrToIntResult StrToInt_results[] = {
54 { "1099", 1099, 1099, 1099 },
55 { "+88987", 0, 88987, 88987 },
56 { "012", 12, 12, 12 },
57 { "-55", -55, -55, -55 },
59 { "0x44ff", 0, 0, 0x44ff },
60 { "+0x44f4", 0, 0, 0x44f4 },
61 { "-0x44fd", 0, 0, 0x44fd },
62 { "+ 88987", 0, 0, 0 },
65 { "+ 0x44f4", 0, 0, 0 },
66 { "--0x44fd", 0, 0, 0 },
67 { " 1999", 0, 1999, 1999 },
68 { " +88987", 0, 88987, 88987 },
69 { " 012", 0, 12, 12 },
70 { " -55", 0, -55, -55 },
71 { " 0x44ff", 0, 0, 0x44ff },
72 { " +0x44f4", 0, 0, 0x44f4 },
73 { " -0x44fd", 0, 0, 0x44fd },
77 /* pStrFormatByteSize64/StrFormatKBSize results */
78 typedef struct tagStrFormatSizeResult
81 const char* byte_size_64;
83 } StrFormatSizeResult;
86 static const StrFormatSizeResult StrFormatSize_results[] = {
87 { -1023, "-1023 bytes", "0 KB"},
88 { -24, "-24 bytes", "0 KB"},
89 { 309, "309 bytes", "1 KB"},
90 { 10191, "9.95 KB", "10 KB"},
91 { 100353, "98.0 KB", "99 KB"},
92 { 1022286, "998 KB", "999 KB"},
93 { 1046862, "0.99 MB", "1,023 KB"},
94 { 1048574619, "999 MB", "1,023,999 KB"},
95 { 1073741775, "0.99 GB", "1,048,576 KB"},
96 { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB"},
97 { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB"},
98 { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB"},
99 { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB"},
100 { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB"},
101 { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB"},
105 /* StrFormatByteSize64/StrFormatKBSize results */
106 typedef struct tagStrFromTimeIntervalResult
110 const char* time_interval;
111 } StrFromTimeIntervalResult;
114 static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
123 { 1000000, 1, " 10 min" },
124 { 1000000, 2, " 16 min" },
125 { 1000000, 3, " 16 min 40 sec" },
126 { 1000000, 4, " 16 min 40 sec" },
127 { 1000000, 5, " 16 min 40 sec" },
128 { 1000000, 6, " 16 min 40 sec" },
129 { 1000000, 7, " 16 min 40 sec" },
131 { 1999999, 1, " 30 min" },
132 { 1999999, 2, " 33 min" },
133 { 1999999, 3, " 33 min 20 sec" },
134 { 1999999, 4, " 33 min 20 sec" },
135 { 1999999, 5, " 33 min 20 sec" },
136 { 1999999, 6, " 33 min 20 sec" },
137 { 1999999, 7, " 33 min 20 sec" },
139 { 3999997, 1, " 1 hr" },
140 { 3999997, 2, " 1 hr 6 min" },
141 { 3999997, 3, " 1 hr 6 min 40 sec" },
142 { 3999997, 4, " 1 hr 6 min 40 sec" },
143 { 3999997, 5, " 1 hr 6 min 40 sec" },
144 { 3999997, 6, " 1 hr 6 min 40 sec" },
145 { 3999997, 7, " 1 hr 6 min 40 sec" },
147 { 149999851, 7, " 41 hr 40 min 0 sec" },
148 { 150999850, 1, " 40 hr" },
149 { 150999850, 2, " 41 hr" },
150 { 150999850, 3, " 41 hr 50 min" },
151 { 150999850, 4, " 41 hr 56 min" },
152 { 150999850, 5, " 41 hr 56 min 40 sec" },
153 { 150999850, 6, " 41 hr 56 min 40 sec" },
154 { 150999850, 7, " 41 hr 56 min 40 sec" },
156 { 493999507, 1, " 100 hr" },
157 { 493999507, 2, " 130 hr" },
158 { 493999507, 3, " 137 hr" },
159 { 493999507, 4, " 137 hr 10 min" },
160 { 493999507, 5, " 137 hr 13 min" },
161 { 493999507, 6, " 137 hr 13 min 20 sec" },
162 { 493999507, 7, " 137 hr 13 min 20 sec" },
167 static void test_StrChrA(void)
172 /* this test crashes on win2k SP4 */
173 /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/
175 for (count = 32; count < 128; count++)
176 string[count] = (char)count;
179 for (count = 32; count < 128; count++)
181 LPSTR result = StrChrA(string+32, count);
182 ok(result - string == count,
183 "found char '%c' in wrong place: got %d, expected %d\n",
184 count, result - string, count);
187 for (count = 32; count < 128; count++)
189 LPSTR result = StrChrA(string+count+1, count);
190 ok(!result, "found char '%c' not in the string\n", count);
194 static void test_StrChrW(void)
199 /* this test crashes on win2k SP4 */
200 /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/
202 for (count = 32; count < 16384; count++)
203 string[count] = count;
204 string[16384] = '\0';
206 for (count = 32; count < 16384; count++)
208 LPWSTR result = StrChrW(string+32, count);
209 ok((result - string) == count, "found char %d in wrong place\n", count);
212 for (count = 32; count < 16384; count++)
214 LPWSTR result = StrChrW(string+count+1, count);
215 ok(!result, "found char not in the string\n");
219 static void test_StrChrIA(void)
224 /* this test crashes on win2k SP4 */
225 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
227 for (count = 32; count < 128; count++)
228 string[count] = (char)count;
231 for (count = 'A'; count <= 'X'; count++)
233 LPSTR result = StrChrIA(string+32, count);
235 ok(result - string == count, "found char '%c' in wrong place\n", count);
236 ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
239 for (count = 'a'; count < 'z'; count++)
241 LPSTR result = StrChrIA(string+count+1, count);
242 ok(!result, "found char not in the string\n");
246 static void test_StrChrIW(void)
251 /* this test crashes on win2k SP4 */
252 /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/
254 for (count = 32; count < 128; count++)
255 string[count] = count;
258 for (count = 'A'; count <= 'X'; count++)
260 LPWSTR result = StrChrIW(string+32, count);
262 ok(result - string == count, "found char '%c' in wrong place\n", count);
263 ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count);
266 for (count = 'a'; count < 'z'; count++)
268 LPWSTR result = StrChrIW(string+count+1, count);
269 ok(!result, "found char not in the string\n");
273 static void test_StrRChrA(void)
278 /* this test crashes on win2k SP4 */
279 /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
281 for (count = 32; count < 128; count++)
282 string[count] = (char)count;
285 for (count = 32; count < 128; count++)
287 LPSTR result = StrRChrA(string+32, NULL, count);
288 ok(result - string == count, "found char %d in wrong place\n", count);
291 for (count = 32; count < 128; count++)
293 LPSTR result = StrRChrA(string+count+1, NULL, count);
294 ok(!result, "found char not in the string\n");
297 for (count = 32; count < 128; count++)
299 LPSTR result = StrRChrA(string+count+1, string + 127, count);
300 ok(!result, "found char not in the string\n");
304 static void test_StrRChrW(void)
309 /* this test crashes on win2k SP4 */
310 /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/
312 for (count = 32; count < 128; count++)
313 string[count] = count;
316 for (count = 32; count < 128; count++)
318 LPWSTR result = StrRChrW(string+32, NULL, count);
319 ok(result - string == count,
320 "found char %d in wrong place: got %d, expected %d\n",
321 count, result - string, count);
324 for (count = 32; count < 128; count++)
326 LPWSTR result = StrRChrW(string+count+1, NULL, count);
327 ok(!result, "found char %d not in the string\n", count);
330 for (count = 32; count < 128; count++)
332 LPWSTR result = StrRChrW(string+count+1, string + 127, count);
333 ok(!result, "found char %d not in the string\n", count);
337 static void test_StrCpyW(void)
341 const StrFormatSizeResult* result = StrFormatSize_results;
346 MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
348 StrCpyW(szBuff, szSrc);
349 ok(!StrCmpW(szSrc, szBuff), "Copied string %s wrong\n", result->byte_size_64);
355 static void test_StrToIntA(void)
357 const StrToIntResult *result = StrToInt_results;
360 while (result->string)
362 return_val = StrToIntA(result->string);
363 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
364 result->string, return_val);
369 static void test_StrToIntW(void)
372 const StrToIntResult *result = StrToInt_results;
375 while (result->string)
377 MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
378 return_val = StrToIntW(szBuff);
379 ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n",
380 result->string, return_val);
385 static void test_StrToIntExA(void)
387 const StrToIntResult *result = StrToInt_results;
391 while (result->string)
394 bRet = StrToIntExA(result->string,0,&return_val);
395 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
398 ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
399 result->string, return_val);
403 result = StrToInt_results;
404 while (result->string)
407 bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val);
408 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
411 ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
412 result->string, return_val);
417 static void test_StrToIntExW(void)
420 const StrToIntResult *result = StrToInt_results;
424 while (result->string)
427 MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
428 bRet = StrToIntExW(szBuff, 0, &return_val);
429 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
432 ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n",
433 result->string, return_val);
437 result = StrToInt_results;
438 while (result->string)
441 MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
442 bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val);
443 ok(!bRet || return_val != -1, "No result returned from '%s'\n",
446 ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n",
447 result->string, return_val);
452 static void test_StrDupA()
455 const StrFormatSizeResult* result = StrFormatSize_results;
459 lpszStr = StrDupA(result->byte_size_64);
461 ok(lpszStr != NULL, "Dup failed\n");
464 ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n");
465 LocalFree((HLOCAL)lpszStr);
470 /* Later versions of shlwapi return NULL for this, but earlier versions
471 * returned an empty string (as Wine does).
473 lpszStr = StrDupA(NULL);
474 ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr);
477 static void test_StrFormatByteSize64A(void)
479 /* this test fails on locales which do not use '.' as a decimal separator */
482 const StrFormatSizeResult* result = StrFormatSize_results;
486 StrFormatByteSize64A(result->value, szBuff, 256);
488 ok(!strcmp(result->byte_size_64, szBuff),
489 "Formatted %lx%08lx wrong: got %s, expected %s\n",
490 (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64);
497 static void test_StrFormatKBSizeW(void)
499 /* FIXME: Awaiting NLS fixes in kernel before these succeed */
503 const StrFormatSizeResult* result = StrFormatSize_results;
507 StrFormatKBSizeW(result->value, szBuffW, 256);
508 WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
509 ok(!strcmp(result->kb_size, szBuff),
510 "Formatted %lx%08lx wrong: got %s, expected %s\n",
511 (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
517 static void test_StrFormatKBSizeA(void)
519 /* this test fails on locales which do not use '.' as a decimal separator */
522 const StrFormatSizeResult* result = StrFormatSize_results;
526 StrFormatKBSizeA(result->value, szBuff, 256);
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);
536 void test_StrFromTimeIntervalA(void)
539 const StrFromTimeIntervalResult* result = StrFromTimeInterval_results;
543 StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
545 ok(!strcmp(result->time_interval, szBuff), "Formatted %ld %d wrong\n",
546 result->ms, result->digits);
551 void test_StrCmpA(void)
553 static const char str1[] = {'a','b','c','d','e','f'};
554 static const char str2[] = {'a','B','c','d','e','f'};
555 ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n");
556 ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n");
557 ok(!ChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n");
558 ok(!ChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n");
559 ok(ChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n");
561 ok(StrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n");
562 ok(!StrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n");
564 ok(IntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n");
565 ok(!IntlStrEqWorkerA(TRUE, str1, str2, 5), "IntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n");
568 void test_StrCmpW(void)
570 static const WCHAR str1[] = {'a','b','c','d','e','f'};
571 static const WCHAR str2[] = {'a','B','c','d','e','f'};
572 ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n");
573 ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n");
574 ok(!ChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n");
575 ok(!ChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n");
576 ok(ChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n");
578 ok(StrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n");
579 ok(!StrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n");
581 ok(IntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n");
582 ok(!IntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n");
585 static WCHAR *CoDupStrW(const char* src)
587 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
588 WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR));
589 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
593 static void test_StrRetToBSTR(void)
596 static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
602 module = GetModuleHandleA("shlwapi");
604 ptr_StrRetToBSTR = (void *)GetProcAddress(module, "StrRetToBSTR");
605 if (!ptr_StrRetToBSTR) return;
607 strret.uType = STRRET_WSTR;
608 strret.u.pOleStr = CoDupStrW("Test");
610 ret = ptr_StrRetToBSTR(&strret, NULL, &bstr);
611 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
612 "STRRET_WSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
616 strret.uType = STRRET_CSTR;
617 lstrcpyA(strret.u.cStr, "Test");
618 ret = ptr_StrRetToBSTR(&strret, NULL, &bstr);
619 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
620 "STRRET_CSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
624 strret.uType = STRRET_OFFSET;
625 strret.u.uOffset = 1;
626 strcpy((char*)&iidl, " Test");
627 ret = ptr_StrRetToBSTR(&strret, iidl, &bstr);
628 ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW),
629 "STRRET_OFFSET: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr);
633 /* Native crashes if str is NULL */
652 test_StrFormatByteSize64A();
653 test_StrFormatKBSizeA();
654 test_StrFormatKBSizeW();
655 test_StrFromTimeIntervalA();