2 * Unit tests for locale functions
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24 * even when the user has overridden their default i8n settings (e.g. in
25 * the control panel i8n page), we will still get the expected results.
33 #include "wine/test.h"
39 static inline unsigned int strlenW( const WCHAR *str )
46 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
49 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
53 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
55 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
59 static inline int isdigitW( WCHAR wc )
62 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
63 return type & C1_DIGIT;
66 /* Some functions are only in later versions of kernel32.dll */
67 static HMODULE hKernel32;
68 static WORD enumCount;
70 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
71 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
72 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
73 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
74 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
75 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
76 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
77 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
78 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
79 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
80 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
81 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
83 static void InitFunctionPointers(void)
85 hKernel32 = GetModuleHandleA("kernel32");
86 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
87 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
88 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
89 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
90 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
91 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
92 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
93 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
94 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
95 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
96 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
97 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
100 #define eq(received, expected, label, type) \
101 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
102 (label), (received), (expected))
104 #define BUFFER_SIZE 128
105 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
107 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
108 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
109 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
110 "Expected '%s', got '%s'\n", Expected, buffer)
112 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
113 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
114 SetLastError(0xdeadbeef); buffer[0] = '\0'
115 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
116 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
118 #define NUO LOCALE_NOUSEROVERRIDE
120 static void test_GetLocaleInfoA(void)
124 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
125 char buffer[BUFFER_SIZE];
126 char expected[BUFFER_SIZE];
128 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
130 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
131 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
132 assumes SUBLANG_NEUTRAL for zh */
133 memset(expected, 0, COUNTOF(expected));
134 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
135 SetLastError(0xdeadbeef);
136 memset(buffer, 0, COUNTOF(buffer));
137 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
138 ok((ret == len) && !lstrcmpA(buffer, expected),
139 "got %d with '%s' (expected %d with '%s')\n",
140 ret, buffer, len, expected);
142 memset(expected, 0, COUNTOF(expected));
143 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
145 SetLastError(0xdeadbeef);
146 memset(buffer, 0, COUNTOF(buffer));
147 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
148 ok((ret == len) && !lstrcmpA(buffer, expected),
149 "got %d with '%s' (expected %d with '%s')\n",
150 ret, buffer, len, expected);
153 win_skip("LANG_ARABIC not installed\n");
155 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
156 memset(expected, 0, COUNTOF(expected));
157 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
158 SetLastError(0xdeadbeef);
159 memset(buffer, 0, COUNTOF(buffer));
160 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
161 ok((ret == len) && !lstrcmpA(buffer, expected),
162 "got %d with '%s' (expected %d with '%s')\n",
163 ret, buffer, len, expected);
166 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
167 * partially fill the buffer even if it is too short. See bug 637.
169 SetLastError(0xdeadbeef);
170 memset(buffer, 0, COUNTOF(buffer));
171 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
172 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
174 SetLastError(0xdeadbeef);
175 memset(buffer, 0, COUNTOF(buffer));
176 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
177 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
178 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
179 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
181 SetLastError(0xdeadbeef);
182 memset(buffer, 0, COUNTOF(buffer));
183 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
184 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
185 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
188 static void test_GetLocaleInfoW(void)
190 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
191 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
192 WCHAR bufferW[80], buffer2W[80];
197 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
199 win_skip("GetLocaleInfoW() isn't implemented\n");
202 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
204 win_skip("LANG_RUSSIAN locale data unavailable\n");
207 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
208 bufferW, COUNTOF(bufferW));
210 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
214 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
216 SetLastError(0xdeadbeef);
217 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
218 bufferA, COUNTOF(bufferA));
219 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
220 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
221 ok(GetLastError() == ERROR_INVALID_FLAGS,
222 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
225 SetLastError(0xdeadbeef);
226 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
227 bufferW, COUNTOF(bufferW));
229 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
230 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
231 ok(GetLastError() == ERROR_INVALID_FLAGS,
232 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
234 /* yes, test empty 13 month entry too */
235 for (i = 0; i < 12; i++) {
237 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
238 bufferW, COUNTOF(bufferW));
239 ok(ret, "Expected non zero result\n");
240 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
241 ret, lstrlenW(bufferW));
243 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
244 buffer2W, COUNTOF(buffer2W));
245 ok(ret, "Expected non zero result\n");
246 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
247 ret, lstrlenW(buffer2W));
249 ok(lstrcmpW(bufferW, buffer2W) != 0,
250 "Expected genitive name to differ, got the same for month %d\n", i+1);
252 /* for locale without genitive names nominative returned in both cases */
254 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
255 bufferW, COUNTOF(bufferW));
256 ok(ret, "Expected non zero result\n");
257 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
258 ret, lstrlenW(bufferW));
260 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
261 buffer2W, COUNTOF(buffer2W));
262 ok(ret, "Expected non zero result\n");
263 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
264 ret, lstrlenW(buffer2W));
266 ok(lstrcmpW(bufferW, buffer2W) == 0,
267 "Expected same names, got different for month %d\n", i+1);
271 static void test_GetTimeFormatA(void)
275 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
276 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
278 memset(&curtime, 2, sizeof(SYSTEMTIME));
279 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
280 SetLastError(0xdeadbeef);
281 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
282 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
283 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
286 curtime.wMinute = 56;
287 curtime.wSecond = 13;
288 curtime.wMilliseconds = 22;
289 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
290 SetLastError(0xdeadbeef);
291 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
292 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
293 EXPECT_LENA; EXPECT_EQA;
295 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
296 SetLastError(0xdeadbeef);
297 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
298 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
299 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
301 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
302 SetLastError(0xdeadbeef);
303 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
304 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
305 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
307 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
308 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
309 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
312 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
313 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
314 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
315 EXPECT_LENA; EXPECT_EQA;
317 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
318 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
319 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
320 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
321 "Expected '', got '%s'\n", buffer );
323 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
324 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
326 EXPECT_LENA; EXPECT_EQA;
328 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
329 strcpy(Expected, "8:56 AM");
330 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
331 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
332 EXPECT_LENA; EXPECT_EQA;
334 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
335 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
336 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
337 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
338 "Expected '8.@:56AM', got '%s'\n", buffer );
340 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
341 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
342 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
343 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
344 "Expected '', got '%s'\n", buffer );
346 STRINGSA("t/tt", "A/AM"); /* AM time marker */
347 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
348 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
349 EXPECT_LENA; EXPECT_EQA;
352 STRINGSA("t/tt", "P/PM"); /* PM time marker */
353 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
354 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
355 EXPECT_LENA; EXPECT_EQA;
357 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
358 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
359 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
360 EXPECT_LENA; EXPECT_EQA;
362 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
363 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
364 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
365 EXPECT_LENA; EXPECT_EQA;
367 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
368 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
369 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
370 EXPECT_LENA; EXPECT_EQA;
372 curtime.wHour = 14; /* change this to 14 or 2pm */
375 STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
376 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
377 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
378 EXPECT_LENA; EXPECT_EQA;
381 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
382 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
383 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
384 EXPECT_LENA; EXPECT_EQA;
386 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
387 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
388 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
389 EXPECT_LENA; EXPECT_EQA;
391 /* try to convert formatting strings with more than two letters
392 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
393 * NOTE: We expect any letter for which there is an upper case value
394 * we should see a replacement. For letters that DO NOT have
395 * upper case values we should see NO REPLACEMENT.
398 curtime.wMinute = 56;
399 curtime.wSecond = 13;
400 curtime.wMilliseconds = 22;
401 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
402 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
403 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
404 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
405 EXPECT_LENA; EXPECT_EQA;
407 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
408 strcpy(buffer, "text");
409 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
410 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
413 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
414 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
415 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
416 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
417 EXPECT_LENA; EXPECT_EQA;
419 STRINGSA("'''", "'"); /* invalid quoted string */
420 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
421 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
422 EXPECT_LENA; EXPECT_EQA;
424 /* test that msdn suggested single quotation usage works as expected */
425 STRINGSA("''''", "'"); /* single quote mark */
426 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
427 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
428 EXPECT_LENA; EXPECT_EQA;
430 STRINGSA("''HHHHHH", "08"); /* Normal use */
431 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
432 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
433 EXPECT_LENA; EXPECT_EQA;
435 /* and test for normal use of the single quotation mark */
436 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
437 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
438 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
439 EXPECT_LENA; EXPECT_EQA;
441 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
442 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
443 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
444 EXPECT_LENA; EXPECT_EQA;
446 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
447 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
448 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
449 EXPECT_LENA; EXPECT_EQA;
452 STRINGSA("'123'tt", ""); /* Invalid time */
453 SetLastError(0xdeadbeef);
454 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
455 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
456 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
459 curtime.wMonth = 60; /* Invalid */
460 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
461 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
462 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
463 EXPECT_LENA; EXPECT_EQA;
466 static void test_GetDateFormatA(void)
470 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
471 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
472 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
473 char Broken[BUFFER_SIZE];
474 char short_day[10], month[10], genitive_month[10];
476 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
477 STRINGSA("ddd',' MMM dd yy","");
478 SetLastError(0xdeadbeef);
479 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
480 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
481 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
483 curtime.wYear = 2002;
486 curtime.wDayOfWeek = 3;
487 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
488 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
489 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
490 EXPECT_LENA; EXPECT_EQA;
492 /* Same as above but with LOCALE_NOUSEROVERRIDE */
493 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
494 SetLastError(0xdeadbeef);
495 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
496 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
497 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
500 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
501 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
503 EXPECT_LENA; EXPECT_EQA;
505 curtime.wHour = 36; /* Invalid */
506 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
507 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
508 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
509 EXPECT_LENA; EXPECT_EQA;
511 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
512 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
513 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
516 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
517 SetLastError(0xdeadbeef);
518 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
519 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
520 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
522 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
523 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
525 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
526 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
528 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
529 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
531 EXPECT_LENA; EXPECT_EQA;
533 /* test for expected DATE_YEARMONTH behavior with null format */
534 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
535 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
536 SetLastError(0xdeadbeef);
537 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
538 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
539 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
542 /* Test that using invalid DATE_* flags results in the correct error */
543 /* and return values */
544 STRINGSA("m/d/y", ""); /* Invalid flags */
545 SetLastError(0xdeadbeef);
546 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
547 &curtime, input, buffer, COUNTOF(buffer));
548 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
549 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
551 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
554 win_skip("LANG_RUSSIAN locale data unavailable\n");
558 /* month part should be in genitive form */
559 strcpy(genitive_month, buffer + 2);
560 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 strcpy(month, buffer);
563 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
565 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
567 strcpy(short_day, buffer);
569 STRINGSA("dd MMMMddd dd", "");
570 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
571 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
575 STRINGSA("MMMMddd dd", "");
576 sprintf(Expected, "%s%s 04", month, short_day);
577 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
581 STRINGSA("MMMMddd", "");
582 sprintf(Expected, "%s%s", month, short_day);
583 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
587 STRINGSA("MMMMdd", "");
588 sprintf(Expected, "%s04", genitive_month);
589 sprintf(Broken, "%s04", month);
590 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
591 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
592 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
593 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
594 "Expected '%s', got '%s'\n", Expected, buffer);
596 STRINGSA("MMMMdd ddd", "");
597 sprintf(Expected, "%s04 %s", genitive_month, short_day);
598 sprintf(Broken, "%s04 %s", month, short_day);
599 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
600 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
601 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
602 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
603 "Expected '%s', got '%s'\n", Expected, buffer);
605 STRINGSA("dd dddMMMM", "");
606 sprintf(Expected, "04 %s%s", short_day, month);
607 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
608 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
611 STRINGSA("dd dddMMMM ddd MMMMdd", "");
612 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
613 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
614 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
615 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
616 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
617 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
618 "Expected '%s', got '%s'\n", Expected, buffer);
620 /* with literal part */
621 STRINGSA("ddd',' MMMM dd", "");
622 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
623 sprintf(Broken, "%s, %s 04", short_day, month);
624 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
625 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
626 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
627 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
628 "Expected '%s', got '%s'\n", Expected, buffer);
631 static void test_GetDateFormatW(void)
635 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
636 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
638 STRINGSW("",""); /* If flags is not zero then format must be NULL */
639 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
640 input, buffer, COUNTOF(buffer));
641 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
643 win_skip("GetDateFormatW is not implemented\n");
646 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
647 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
650 STRINGSW("",""); /* NULL buffer, len > 0 */
651 SetLastError(0xdeadbeef);
652 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
653 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
654 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
656 STRINGSW("",""); /* NULL buffer, len == 0 */
657 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
658 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
659 EXPECT_LENW; EXPECT_EQW;
661 curtime.wYear = 2002;
664 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
665 curtime.wHour = 65432; /* Invalid */
666 curtime.wMinute = 34512; /* Invalid */
667 curtime.wSecond = 65535; /* Invalid */
668 curtime.wMilliseconds = 12345;
669 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
670 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
672 EXPECT_LENW; EXPECT_EQW;
676 curtime.wYear = 1601;
679 curtime.wDayOfWeek = 0; /* Irrelevant */
683 curtime.wMilliseconds = 0;
684 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
685 SetLastError(0xdeadbeef);
686 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
687 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
688 EXPECT_LENW; EXPECT_EQW;
690 curtime.wYear = 1600;
693 curtime.wDayOfWeek = 0; /* Irrelevant */
695 curtime.wMinute = 59;
696 curtime.wSecond = 59;
697 curtime.wMilliseconds = 999;
698 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
699 SetLastError(0xdeadbeef);
700 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
702 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
706 #define CY_POS_LEFT 0
707 #define CY_POS_RIGHT 1
708 #define CY_POS_LEFT_SPACE 2
709 #define CY_POS_RIGHT_SPACE 3
711 static void test_GetCurrencyFormatA(void)
713 static char szDot[] = { '.', '\0' };
714 static char szComma[] = { ',', '\0' };
715 static char szDollar[] = { '$', '\0' };
717 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
718 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
721 memset(&format, 0, sizeof(format));
723 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
724 SetLastError(0xdeadbeef);
725 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
726 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
727 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
729 STRINGSA("23,53",""); /* Invalid character --> Error */
730 SetLastError(0xdeadbeef);
731 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
732 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
733 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
735 STRINGSA("--",""); /* Double '-' --> Error */
736 SetLastError(0xdeadbeef);
737 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
738 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
739 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
741 STRINGSA("0-",""); /* Trailing '-' --> Error */
742 SetLastError(0xdeadbeef);
743 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
744 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
745 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
747 STRINGSA("0..",""); /* Double '.' --> Error */
748 SetLastError(0xdeadbeef);
749 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
750 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
751 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
753 STRINGSA(" 0.1",""); /* Leading space --> Error */
754 SetLastError(0xdeadbeef);
755 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
756 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
757 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
759 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
760 SetLastError(0xdeadbeef);
761 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
762 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
763 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
765 STRINGSA("2353",""); /* Format and flags given --> Error */
766 SetLastError(0xdeadbeef);
767 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
768 ok( !ret, "Expected ret == 0, got %d\n", ret);
769 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
770 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
772 STRINGSA("2353",""); /* Invalid format --> Error */
773 SetLastError(0xdeadbeef);
774 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
775 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
776 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
778 STRINGSA("2353","$2,353.00"); /* Valid number */
779 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
780 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781 EXPECT_LENA; EXPECT_EQA;
783 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
784 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENA; EXPECT_EQA;
788 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
789 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
790 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
791 EXPECT_LENA; EXPECT_EQA;
793 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
794 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
795 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
796 EXPECT_LENA; EXPECT_EQA;
798 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
799 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
800 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
801 EXPECT_LENA; EXPECT_EQA;
803 format.NumDigits = 0; /* No decimal separator */
804 format.LeadingZero = 0;
805 format.Grouping = 0; /* No grouping char */
806 format.NegativeOrder = 0;
807 format.PositiveOrder = CY_POS_LEFT;
808 format.lpDecimalSep = szDot;
809 format.lpThousandSep = szComma;
810 format.lpCurrencySymbol = szDollar;
812 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
813 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
814 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
815 EXPECT_LENA; EXPECT_EQA;
817 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
818 STRINGSA("2353","$2353.0");
819 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
820 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
821 EXPECT_LENA; EXPECT_EQA;
823 format.Grouping = 2; /* Group by 100's */
824 STRINGSA("2353","$23,53.0");
825 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
826 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
827 EXPECT_LENA; EXPECT_EQA;
829 STRINGSA("235","$235.0"); /* Grouping of a positive number */
831 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
832 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
833 EXPECT_LENA; EXPECT_EQA;
835 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
836 format.NegativeOrder = 2;
837 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
838 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
839 EXPECT_LENA; EXPECT_EQA;
841 format.LeadingZero = 1; /* Always provide leading zero */
842 STRINGSA(".5","$0.5");
843 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
844 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
845 EXPECT_LENA; EXPECT_EQA;
847 format.PositiveOrder = CY_POS_RIGHT;
848 STRINGSA("1","1.0$");
849 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
850 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
851 EXPECT_LENA; EXPECT_EQA;
853 format.PositiveOrder = CY_POS_LEFT_SPACE;
854 STRINGSA("1","$ 1.0");
855 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
856 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
857 EXPECT_LENA; EXPECT_EQA;
859 format.PositiveOrder = CY_POS_RIGHT_SPACE;
860 STRINGSA("1","1.0 $");
861 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
862 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
863 EXPECT_LENA; EXPECT_EQA;
865 format.NegativeOrder = 0;
866 STRINGSA("-1","($1.0)");
867 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
868 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
869 EXPECT_LENA; EXPECT_EQA;
871 format.NegativeOrder = 1;
872 STRINGSA("-1","-$1.0");
873 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
874 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
875 EXPECT_LENA; EXPECT_EQA;
877 format.NegativeOrder = 2;
878 STRINGSA("-1","$-1.0");
879 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
880 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
881 EXPECT_LENA; EXPECT_EQA;
883 format.NegativeOrder = 3;
884 STRINGSA("-1","$1.0-");
885 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
886 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
887 EXPECT_LENA; EXPECT_EQA;
889 format.NegativeOrder = 4;
890 STRINGSA("-1","(1.0$)");
891 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
892 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
893 EXPECT_LENA; EXPECT_EQA;
895 format.NegativeOrder = 5;
896 STRINGSA("-1","-1.0$");
897 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
898 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
899 EXPECT_LENA; EXPECT_EQA;
901 format.NegativeOrder = 6;
902 STRINGSA("-1","1.0-$");
903 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
904 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
905 EXPECT_LENA; EXPECT_EQA;
907 format.NegativeOrder = 7;
908 STRINGSA("-1","1.0$-");
909 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
910 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
911 EXPECT_LENA; EXPECT_EQA;
913 format.NegativeOrder = 8;
914 STRINGSA("-1","-1.0 $");
915 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 EXPECT_LENA; EXPECT_EQA;
919 format.NegativeOrder = 9;
920 STRINGSA("-1","-$ 1.0");
921 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
922 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
923 EXPECT_LENA; EXPECT_EQA;
925 format.NegativeOrder = 10;
926 STRINGSA("-1","1.0 $-");
927 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
928 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
929 EXPECT_LENA; EXPECT_EQA;
931 format.NegativeOrder = 11;
932 STRINGSA("-1","$ 1.0-");
933 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
934 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
935 EXPECT_LENA; EXPECT_EQA;
937 format.NegativeOrder = 12;
938 STRINGSA("-1","$ -1.0");
939 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
940 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
941 EXPECT_LENA; EXPECT_EQA;
943 format.NegativeOrder = 13;
944 STRINGSA("-1","1.0- $");
945 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 EXPECT_LENA; EXPECT_EQA;
949 format.NegativeOrder = 14;
950 STRINGSA("-1","($ 1.0)");
951 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
952 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
953 EXPECT_LENA; EXPECT_EQA;
955 format.NegativeOrder = 15;
956 STRINGSA("-1","(1.0 $)");
957 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
958 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
959 EXPECT_LENA; EXPECT_EQA;
962 #define NEG_PARENS 0 /* "(1.1)" */
963 #define NEG_LEFT 1 /* "-1.1" */
964 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
965 #define NEG_RIGHT 3 /* "1.1-" */
966 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
968 static void test_GetNumberFormatA(void)
970 static char szDot[] = { '.', '\0' };
971 static char szComma[] = { ',', '\0' };
973 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
974 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
977 memset(&format, 0, sizeof(format));
979 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
980 SetLastError(0xdeadbeef);
981 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
982 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
983 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
985 STRINGSA("23,53",""); /* Invalid character --> Error */
986 SetLastError(0xdeadbeef);
987 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
988 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
989 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
991 STRINGSA("--",""); /* Double '-' --> Error */
992 SetLastError(0xdeadbeef);
993 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
994 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
995 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
997 STRINGSA("0-",""); /* Trailing '-' --> Error */
998 SetLastError(0xdeadbeef);
999 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1000 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1001 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1003 STRINGSA("0..",""); /* Double '.' --> Error */
1004 SetLastError(0xdeadbeef);
1005 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1006 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1007 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1009 STRINGSA(" 0.1",""); /* Leading space --> Error */
1010 SetLastError(0xdeadbeef);
1011 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1012 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1013 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1015 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1016 SetLastError(0xdeadbeef);
1017 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1018 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1019 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1021 STRINGSA("2353",""); /* Format and flags given --> Error */
1022 SetLastError(0xdeadbeef);
1023 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1024 ok( !ret, "Expected ret == 0, got %d\n", ret);
1025 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1026 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1028 STRINGSA("2353",""); /* Invalid format --> Error */
1029 SetLastError(0xdeadbeef);
1030 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1031 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1032 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1034 STRINGSA("2353","2,353.00"); /* Valid number */
1035 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1036 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1037 EXPECT_LENA; EXPECT_EQA;
1039 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1040 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1041 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1042 EXPECT_LENA; EXPECT_EQA;
1044 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1045 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1046 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1047 EXPECT_LENA; EXPECT_EQA;
1049 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1050 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1051 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1052 EXPECT_LENA; EXPECT_EQA;
1054 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1055 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1056 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1057 EXPECT_LENA; EXPECT_EQA;
1059 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1060 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1061 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1062 EXPECT_LENA; EXPECT_EQA;
1064 format.NumDigits = 0; /* No decimal separator */
1065 format.LeadingZero = 0;
1066 format.Grouping = 0; /* No grouping char */
1067 format.NegativeOrder = 0;
1068 format.lpDecimalSep = szDot;
1069 format.lpThousandSep = szComma;
1071 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1072 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1073 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1074 EXPECT_LENA; EXPECT_EQA;
1076 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1077 STRINGSA("2353","2353.0");
1078 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1079 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1080 EXPECT_LENA; EXPECT_EQA;
1082 format.Grouping = 2; /* Group by 100's */
1083 STRINGSA("2353","23,53.0");
1084 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1085 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1086 EXPECT_LENA; EXPECT_EQA;
1088 STRINGSA("235","235.0"); /* Grouping of a positive number */
1089 format.Grouping = 3;
1090 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1091 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1092 EXPECT_LENA; EXPECT_EQA;
1094 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1095 format.NegativeOrder = NEG_LEFT;
1096 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1097 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1098 EXPECT_LENA; EXPECT_EQA;
1100 format.LeadingZero = 1; /* Always provide leading zero */
1101 STRINGSA(".5","0.5");
1102 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1103 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1104 EXPECT_LENA; EXPECT_EQA;
1106 format.NegativeOrder = NEG_PARENS;
1107 STRINGSA("-1","(1.0)");
1108 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENA; EXPECT_EQA;
1112 format.NegativeOrder = NEG_LEFT;
1113 STRINGSA("-1","-1.0");
1114 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1115 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1116 EXPECT_LENA; EXPECT_EQA;
1118 format.NegativeOrder = NEG_LEFT_SPACE;
1119 STRINGSA("-1","- 1.0");
1120 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1121 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1122 EXPECT_LENA; EXPECT_EQA;
1124 format.NegativeOrder = NEG_RIGHT;
1125 STRINGSA("-1","1.0-");
1126 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1127 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1128 EXPECT_LENA; EXPECT_EQA;
1130 format.NegativeOrder = NEG_RIGHT_SPACE;
1131 STRINGSA("-1","1.0 -");
1132 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1133 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1134 EXPECT_LENA; EXPECT_EQA;
1136 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1138 if (IsValidLocale(lcid, 0))
1140 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1141 Expected[3] = 160; /* Non breaking space */
1142 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1143 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1144 EXPECT_LENA; EXPECT_EQA;
1148 struct comparestringa_entry {
1158 static const struct comparestringa_entry comparestringa_data[] = {
1159 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1160 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1161 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1162 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1163 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1164 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1165 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1166 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1167 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1168 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1169 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1170 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1171 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1172 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1173 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1174 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1175 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1176 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1177 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1178 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1179 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1180 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1181 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1182 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1183 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1184 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1185 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1186 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1187 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1188 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1191 static void test_CompareStringA(void)
1194 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1196 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1198 const struct comparestringa_entry *entry = &comparestringa_data[i];
1200 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1201 entry->second, entry->second_len);
1202 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1205 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1206 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1208 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1209 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1211 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1212 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1214 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1215 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1217 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1219 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1220 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1222 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1223 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1225 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1226 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1228 /* test for CompareStringA flags */
1229 SetLastError(0xdeadbeef);
1230 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1231 ok(GetLastError() == ERROR_INVALID_FLAGS,
1232 "unexpected error code %d\n", GetLastError());
1233 ok(!ret, "CompareStringA must fail with invalid flag\n");
1235 SetLastError(0xdeadbeef);
1236 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1237 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1238 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1239 /* end of test for CompareStringA flags */
1241 ret = lstrcmpA("", "");
1242 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1244 ret = lstrcmpA(NULL, NULL);
1245 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1247 ret = lstrcmpA("", NULL);
1248 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1250 ret = lstrcmpA(NULL, "");
1251 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1254 if (0) { /* this requires collation table patch to make it MS compatible */
1255 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1256 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1258 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1259 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1261 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1262 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1264 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1265 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1267 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1268 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1270 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1271 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1273 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1274 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1276 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1277 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1279 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1280 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1282 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1283 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1285 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1286 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1288 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1289 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1293 /* WinXP handles embedded NULLs differently than earlier versions */
1294 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1295 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1297 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1298 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1300 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1301 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1303 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1304 ok(ret == CSTR_EQUAL || /* win2k */
1305 ret == CSTR_GREATER_THAN,
1306 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1308 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1309 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1311 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1312 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1314 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1315 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1317 ret = lstrcmpi("#", ".");
1318 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1320 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1322 /* \xB9 character lies between a and b */
1323 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1324 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1325 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1326 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1329 static void test_LCMapStringA(void)
1332 char buf[256], buf2[256];
1333 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1334 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1335 static const char symbols_stripped[] = "justateststring1";
1337 SetLastError(0xdeadbeef);
1338 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1339 lower_case, -1, buf, sizeof(buf));
1340 ok(ret == lstrlenA(lower_case) + 1,
1341 "ret %d, error %d, expected value %d\n",
1342 ret, GetLastError(), lstrlenA(lower_case) + 1);
1343 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1345 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1346 upper_case, -1, buf, sizeof(buf));
1347 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1348 ok(GetLastError() == ERROR_INVALID_FLAGS,
1349 "unexpected error code %d\n", GetLastError());
1351 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1352 upper_case, -1, buf, sizeof(buf));
1353 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1354 ok(GetLastError() == ERROR_INVALID_FLAGS,
1355 "unexpected error code %d\n", GetLastError());
1357 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1358 upper_case, -1, buf, sizeof(buf));
1359 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1360 ok(GetLastError() == ERROR_INVALID_FLAGS,
1361 "unexpected error code %d\n", GetLastError());
1363 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1364 upper_case, -1, buf, sizeof(buf));
1365 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1366 ok(GetLastError() == ERROR_INVALID_FLAGS,
1367 "unexpected error code %d\n", GetLastError());
1369 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1370 SetLastError(0xdeadbeef);
1371 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1372 upper_case, -1, buf, sizeof(buf));
1373 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1374 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1376 /* test LCMAP_LOWERCASE */
1377 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1378 upper_case, -1, buf, sizeof(buf));
1379 ok(ret == lstrlenA(upper_case) + 1,
1380 "ret %d, error %d, expected value %d\n",
1381 ret, GetLastError(), lstrlenA(upper_case) + 1);
1382 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1384 /* test LCMAP_UPPERCASE */
1385 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1386 lower_case, -1, buf, sizeof(buf));
1387 ok(ret == lstrlenA(lower_case) + 1,
1388 "ret %d, error %d, expected value %d\n",
1389 ret, GetLastError(), lstrlenA(lower_case) + 1);
1390 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1392 /* test buffer overflow */
1393 SetLastError(0xdeadbeef);
1394 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1395 lower_case, -1, buf, 4);
1396 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1397 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1399 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1400 lstrcpyA(buf, lower_case);
1401 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1402 buf, -1, buf, sizeof(buf));
1403 if (!ret) /* Win9x */
1404 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1407 ok(ret == lstrlenA(lower_case) + 1,
1408 "ret %d, error %d, expected value %d\n",
1409 ret, GetLastError(), lstrlenA(lower_case) + 1);
1410 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1412 lstrcpyA(buf, upper_case);
1413 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1414 buf, -1, buf, sizeof(buf));
1415 if (!ret) /* Win9x */
1416 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1419 ok(ret == lstrlenA(upper_case) + 1,
1420 "ret %d, error %d, expected value %d\n",
1421 ret, GetLastError(), lstrlenA(lower_case) + 1);
1422 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1425 /* otherwise src == dst should fail */
1426 SetLastError(0xdeadbeef);
1427 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1428 buf, 10, buf, sizeof(buf));
1429 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1430 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1431 "unexpected error code %d\n", GetLastError());
1432 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1434 /* test whether '\0' is always appended */
1435 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1436 upper_case, -1, buf, sizeof(buf));
1437 ok(ret, "LCMapStringA must succeed\n");
1438 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1439 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1440 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1441 ok(ret2, "LCMapStringA must succeed\n");
1442 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1443 ok(ret == ret2, "lengths of sort keys must be equal\n");
1444 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1446 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1447 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1448 upper_case, -1, buf, sizeof(buf));
1449 ok(ret, "LCMapStringA must succeed\n");
1450 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1451 lower_case, -1, buf2, sizeof(buf2));
1452 ok(ret2, "LCMapStringA must succeed\n");
1453 ok(ret == ret2, "lengths of sort keys must be equal\n");
1454 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1456 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1457 results from plain LCMAP_SORTKEY on Vista */
1459 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1460 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1461 lower_case, -1, buf, sizeof(buf));
1462 ok(ret, "LCMapStringA must succeed\n");
1463 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1464 symbols_stripped, -1, buf2, sizeof(buf2));
1465 ok(ret2, "LCMapStringA must succeed\n");
1466 ok(ret == ret2, "lengths of sort keys must be equal\n");
1467 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1469 /* test NORM_IGNORENONSPACE */
1470 lstrcpyA(buf, "foo");
1471 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1472 lower_case, -1, buf, sizeof(buf));
1473 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1474 lstrlenA(lower_case) + 1, ret);
1475 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1477 /* test NORM_IGNORESYMBOLS */
1478 lstrcpyA(buf, "foo");
1479 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1480 lower_case, -1, buf, sizeof(buf));
1481 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1482 lstrlenA(symbols_stripped) + 1, ret);
1483 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1485 /* test srclen = 0 */
1486 SetLastError(0xdeadbeef);
1487 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1488 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1489 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1490 "unexpected error code %d\n", GetLastError());
1493 static void test_LCMapStringW(void)
1496 WCHAR buf[256], buf2[256];
1497 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1498 static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
1499 static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
1500 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1501 static const WCHAR fooW[] = {'f','o','o',0};
1503 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1504 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1505 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1507 win_skip("LCMapStringW is not implemented\n");
1511 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1514 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1515 ok(GetLastError() == ERROR_INVALID_FLAGS,
1516 "unexpected error code %d\n", GetLastError());
1519 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1520 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1521 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1522 ok(GetLastError() == ERROR_INVALID_FLAGS,
1523 "unexpected error code %d\n", GetLastError());
1525 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1526 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1527 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1528 ok(GetLastError() == ERROR_INVALID_FLAGS,
1529 "unexpected error code %d\n", GetLastError());
1531 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1532 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1533 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1534 ok(GetLastError() == ERROR_INVALID_FLAGS,
1535 "unexpected error code %d\n", GetLastError());
1537 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1538 SetLastError(0xdeadbeef);
1539 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1540 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1541 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1542 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1544 /* test LCMAP_LOWERCASE */
1545 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1546 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1547 ok(ret == lstrlenW(upper_case) + 1,
1548 "ret %d, error %d, expected value %d\n",
1549 ret, GetLastError(), lstrlenW(upper_case) + 1);
1550 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1552 /* test LCMAP_UPPERCASE */
1553 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1554 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1555 ok(ret == lstrlenW(lower_case) + 1,
1556 "ret %d, error %d, expected value %d\n",
1557 ret, GetLastError(), lstrlenW(lower_case) + 1);
1558 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1560 /* test buffer overflow */
1561 SetLastError(0xdeadbeef);
1562 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1563 lower_case, -1, buf, 4);
1564 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1565 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1567 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1568 lstrcpyW(buf, lower_case);
1569 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1570 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1571 ok(ret == lstrlenW(lower_case) + 1,
1572 "ret %d, error %d, expected value %d\n",
1573 ret, GetLastError(), lstrlenW(lower_case) + 1);
1574 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1576 lstrcpyW(buf, upper_case);
1577 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1578 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1579 ok(ret == lstrlenW(upper_case) + 1,
1580 "ret %d, error %d, expected value %d\n",
1581 ret, GetLastError(), lstrlenW(lower_case) + 1);
1582 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1584 /* otherwise src == dst should fail */
1585 SetLastError(0xdeadbeef);
1586 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1587 buf, 10, buf, sizeof(buf));
1588 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1589 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1590 "unexpected error code %d\n", GetLastError());
1591 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1593 /* test whether '\0' is always appended */
1594 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1595 upper_case, -1, buf, sizeof(buf));
1596 ok(ret, "LCMapStringW must succeed\n");
1597 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1598 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1599 ok(ret, "LCMapStringW must succeed\n");
1600 ok(ret == ret2, "lengths of sort keys must be equal\n");
1601 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1603 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1604 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1605 upper_case, -1, buf, sizeof(buf));
1606 ok(ret, "LCMapStringW must succeed\n");
1607 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1608 lower_case, -1, buf2, sizeof(buf2));
1609 ok(ret2, "LCMapStringW must succeed\n");
1610 ok(ret == ret2, "lengths of sort keys must be equal\n");
1611 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1613 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1614 results from plain LCMAP_SORTKEY on Vista */
1616 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1617 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1618 lower_case, -1, buf, sizeof(buf));
1619 ok(ret, "LCMapStringW must succeed\n");
1620 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1621 symbols_stripped, -1, buf2, sizeof(buf2));
1622 ok(ret2, "LCMapStringW must succeed\n");
1623 ok(ret == ret2, "lengths of sort keys must be equal\n");
1624 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1626 /* test NORM_IGNORENONSPACE */
1627 lstrcpyW(buf, fooW);
1628 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1629 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1630 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1631 lstrlenW(lower_case) + 1, ret);
1632 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1634 /* test NORM_IGNORESYMBOLS */
1635 lstrcpyW(buf, fooW);
1636 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1637 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1638 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1639 lstrlenW(symbols_stripped) + 1, ret);
1640 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1642 /* test srclen = 0 */
1643 SetLastError(0xdeadbeef);
1644 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1645 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1646 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1647 "unexpected error code %d\n", GetLastError());
1650 static void test_LocaleNames(void)
1654 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1656 if (!pLocaleNameToLCID)
1658 win_skip( "LocaleNameToLCID not available\n" );
1664 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1665 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1666 "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1667 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1668 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1669 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1672 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1673 todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1674 "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1675 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1676 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1677 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1680 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1681 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1682 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1683 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1684 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1687 /* this requires collation table patch to make it MS compatible */
1688 static const char * const strings_sorted[] =
1720 static const char * const strings[] =
1752 static int compare_string1(const void *e1, const void *e2)
1754 const char *s1 = *(const char *const *)e1;
1755 const char *s2 = *(const char *const *)e2;
1757 return lstrcmpA(s1, s2);
1760 static int compare_string2(const void *e1, const void *e2)
1762 const char *s1 = *(const char *const *)e1;
1763 const char *s2 = *(const char *const *)e2;
1765 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1768 static int compare_string3(const void *e1, const void *e2)
1770 const char *s1 = *(const char *const *)e1;
1771 const char *s2 = *(const char *const *)e2;
1772 char key1[256], key2[256];
1774 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1775 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1776 return strcmp(key1, key2);
1779 static void test_sorting(void)
1782 char **str_buf = (char **)buf;
1785 assert(sizeof(buf) >= sizeof(strings));
1787 /* 1. sort using lstrcmpA */
1788 memcpy(buf, strings, sizeof(strings));
1789 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1790 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1792 ok(!strcmp(strings_sorted[i], str_buf[i]),
1793 "qsort using lstrcmpA failed for element %d\n", i);
1795 /* 2. sort using CompareStringA */
1796 memcpy(buf, strings, sizeof(strings));
1797 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1798 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1800 ok(!strcmp(strings_sorted[i], str_buf[i]),
1801 "qsort using CompareStringA failed for element %d\n", i);
1803 /* 3. sort using sort keys */
1804 memcpy(buf, strings, sizeof(strings));
1805 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1806 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1808 ok(!strcmp(strings_sorted[i], str_buf[i]),
1809 "qsort using sort keys failed for element %d\n", i);
1813 static void test_FoldStringA(void)
1817 char src[256], dst[256];
1818 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1819 static const char digits_dst[] = { '1','2','3','\0' };
1820 static const char composite_src[] =
1822 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1823 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1824 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1825 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1826 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1827 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1828 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1829 0xfb,0xfc,0xfd,0xff,'\0'
1831 static const char composite_dst[] =
1833 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1834 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1835 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1836 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1837 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1838 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1839 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1840 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1841 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1842 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1843 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1844 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1845 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1846 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1847 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1849 static const char composite_dst_alt[] =
1851 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1852 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1853 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1854 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1855 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1856 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1857 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1858 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1859 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1860 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1861 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1862 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1863 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1864 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1865 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1867 static const char ligatures_src[] =
1869 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1871 static const char ligatures_dst[] =
1873 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1875 static const struct special
1879 } foldczone_special[] =
1882 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1883 { 0x98, { 0x20, 0x7e, 0x00 } },
1884 { 0x99, { 0x54, 0x4d, 0x00 } },
1885 { 0xa0, { 0x20, 0x00 } },
1886 { 0xa8, { 0x20, 0xa8, 0x00 } },
1887 { 0xaa, { 0x61, 0x00 } },
1888 { 0xaf, { 0x20, 0xaf, 0x00 } },
1889 { 0xb2, { 0x32, 0x00 } },
1890 { 0xb3, { 0x33, 0x00 } },
1891 { 0xb4, { 0x20, 0xb4, 0x00 } },
1892 { 0xb8, { 0x20, 0xb8, 0x00 } },
1893 { 0xb9, { 0x31, 0x00 } },
1894 { 0xba, { 0x6f, 0x00 } },
1895 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1896 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1897 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1902 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1904 /* these tests are locale specific */
1905 if (GetACP() != 1252)
1907 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1911 /* MAP_FOLDDIGITS */
1913 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1914 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1916 win_skip("FoldStringA is not implemented\n");
1919 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1920 ok(strcmp(dst, digits_dst) == 0,
1921 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1922 for (i = 1; i < 256; i++)
1924 if (!strchr(digits_src, i))
1929 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1930 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1931 ok(dst[0] == src[0],
1932 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1936 /* MAP_EXPAND_LIGATURES */
1938 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1939 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1940 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1941 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1942 ok(strcmp(dst, ligatures_dst) == 0,
1943 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1944 for (i = 1; i < 256; i++)
1946 if (!strchr(ligatures_src, i))
1951 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1955 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1956 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1957 "Got %s for %d\n", dst, i);
1961 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1962 ok(dst[0] == src[0],
1963 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1971 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1972 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1973 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1974 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1975 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1977 for (i = 1; i < 256; i++)
1979 if (!strchr(composite_src, i))
1984 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1985 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1986 ok(dst[0] == src[0],
1987 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1988 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1993 for (i = 1; i < 256; i++)
1998 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2000 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2002 if (foldczone_special[j].src == src[0])
2004 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2005 "Expected ret == 2 or %d, got %d, error %d\n",
2006 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2007 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2008 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2009 (unsigned char)src[0]);
2015 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2016 ok(src[0] == dst[0],
2017 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2018 (unsigned char)src[0], (unsigned char)dst[0]);
2022 /* MAP_PRECOMPOSED */
2023 for (i = 1; i < 256; i++)
2028 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2029 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2030 ok(src[0] == dst[0],
2031 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2032 (unsigned char)src[0], (unsigned char)dst[0]);
2036 static void test_FoldStringW(void)
2040 WCHAR src[256], dst[256], ch, prev_ch = 1;
2041 static const DWORD badFlags[] =
2044 MAP_PRECOMPOSED|MAP_COMPOSITE,
2045 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2046 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2048 /* Ranges of digits 0-9 : Must be sorted! */
2049 static const WCHAR digitRanges[] =
2051 0x0030, /* '0'-'9' */
2052 0x0660, /* Eastern Arabic */
2053 0x06F0, /* Arabic - Hindu */
2054 0x0966, /* Devengari */
2055 0x09E6, /* Bengalii */
2056 0x0A66, /* Gurmukhi */
2057 0x0AE6, /* Gujarati */
2059 0x0BE6, /* Tamil - No 0 */
2060 0x0C66, /* Telugu */
2061 0x0CE6, /* Kannada */
2062 0x0D66, /* Maylayalam */
2065 0x0F29, /* Tibet - 0 is out of sequence */
2066 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2067 0x2080, /* Subscript */
2068 0x245F, /* Circled - 0 is out of sequence */
2069 0x2473, /* Bracketed */
2070 0x2487, /* Full stop */
2071 0x2775, /* Inverted circled - No 0 */
2072 0x277F, /* Patterned circled - No 0 */
2073 0x2789, /* Inverted Patterned circled - No 0 */
2074 0x3020, /* Hangzhou */
2075 0xff10, /* Pliene chasse (?) */
2076 0xffff /* Terminator */
2078 /* Digits which are represented, but out of sequence */
2079 static const WCHAR outOfSequenceDigits[] =
2081 0xB9, /* Superscript 1 */
2082 0xB2, /* Superscript 2 */
2083 0xB3, /* Superscript 3 */
2084 0x0F33, /* Tibetan half zero */
2085 0x24EA, /* Circled 0 */
2086 0x3007, /* Ideographic number zero */
2087 '\0' /* Terminator */
2089 /* Digits in digitRanges for which no representation is available */
2090 static const WCHAR noDigitAvailable[] =
2092 0x0BE6, /* No Tamil 0 */
2093 0x0F29, /* No Tibetan half zero (out of sequence) */
2094 0x2473, /* No Bracketed 0 */
2095 0x2487, /* No 0 Full stop */
2096 0x2775, /* No inverted circled 0 */
2097 0x277F, /* No patterned circled */
2098 0x2789, /* No inverted Patterned circled */
2099 0x3020, /* No Hangzhou 0 */
2100 '\0' /* Terminator */
2102 static const WCHAR foldczone_src[] =
2104 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2105 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2107 static const WCHAR foldczone_dst[] =
2109 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2111 static const WCHAR foldczone_todo_src[] =
2113 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2115 static const WCHAR foldczone_todo_dst[] =
2117 0x3cb,0x1f0,' ','a',0
2119 static const WCHAR foldczone_todo_broken_dst[] =
2121 0x3cb,0x1f0,0xa0,0xaa,0
2123 static const WCHAR ligatures_src[] =
2125 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2126 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2127 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2128 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2129 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2130 0xfb04, 0xfb05, 0xfb06, '\0'
2132 static const WCHAR ligatures_dst[] =
2134 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2135 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2136 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2137 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2138 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2139 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2144 win_skip("FoldStringW is not available\n");
2145 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2148 /* Invalid flag combinations */
2149 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2151 src[0] = dst[0] = '\0';
2153 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2154 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2156 win_skip("FoldStringW is not implemented\n");
2159 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2160 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2163 /* src & dst cannot be the same */
2165 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2166 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2167 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2169 /* src can't be NULL */
2171 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2172 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2173 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2175 /* srclen can't be 0 */
2177 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2178 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2179 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2181 /* dstlen can't be < 0 */
2183 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2184 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2185 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2187 /* Ret includes terminating NUL which is appended if srclen = -1 */
2192 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2193 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2194 ok(dst[0] == 'A' && dst[1] == '\0',
2195 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2196 'A', '\0', ret, dst[0], dst[1], GetLastError());
2198 /* If size is given, result is not NUL terminated */
2204 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2205 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2206 ok(dst[0] == 'A' && dst[1] == 'X',
2207 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2208 'A','X', ret, dst[0], dst[1], GetLastError());
2210 /* MAP_FOLDDIGITS */
2211 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2213 /* Check everything before this range */
2214 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2218 src[1] = dst[0] = '\0';
2219 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2220 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2222 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2223 /* Wine (correctly) maps all Unicode 4.0+ digits */
2224 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2225 (ch >= 0x1369 && ch <= 0x1371),
2226 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2229 if (digitRanges[j] == 0xffff)
2230 break; /* Finished the whole code point space */
2232 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2236 /* Map out of sequence characters */
2237 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2238 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2239 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2240 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2244 src[1] = dst[0] = '\0';
2245 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2246 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2248 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2249 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2250 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2251 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2252 strchrW(noDigitAvailable, c),
2253 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2254 ch, '0' + digitRanges[j] - ch, dst[0]);
2261 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2262 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2263 "Got %d, error %d\n", ret, GetLastError());
2264 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2265 "MAP_FOLDCZONE: Expanded incorrectly\n");
2267 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2268 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2269 "Got %d, error %d\n", ret, GetLastError());
2270 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2271 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2272 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2274 /* MAP_EXPAND_LIGATURES */
2276 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2277 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2278 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2279 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2280 "Got %d, error %d\n", ret, GetLastError());
2281 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2282 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2285 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2290 #define LCID_OK(l) \
2291 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2292 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2293 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2294 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2295 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2297 static void test_ConvertDefaultLocale(void)
2301 /* Doesn't change lcid, even if non default sublang/sort used */
2302 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2303 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2304 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2305 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2307 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2308 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2309 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2310 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2311 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2313 /* Invariant language is not treated specially */
2314 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2316 /* User/system default languages alone are not mapped */
2317 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2318 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2321 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2322 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2323 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2326 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2327 DWORD dwFlags, LONG_PTR lParam)
2329 trace("%08x, %s, %s, %08x, %08lx\n",
2330 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2332 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2333 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2335 /* If lParam is one, we are calling with flags defaulted from 0 */
2336 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2337 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2342 static void test_EnumSystemLanguageGroupsA(void)
2346 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2348 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2352 /* No enumeration proc */
2354 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2355 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2357 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2360 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2361 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2365 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2366 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2368 /* No flags - defaults to LGRPID_INSTALLED */
2369 SetLastError(0xdeadbeef);
2370 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2371 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2373 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2374 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2377 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2379 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2383 static void test_EnumSystemLocalesEx(void)
2387 if (!pEnumSystemLocalesEx)
2389 win_skip( "EnumSystemLocalesEx not available\n" );
2392 SetLastError( 0xdeadbeef );
2393 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2394 ok( !ret, "should have failed\n" );
2395 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2396 SetLastError( 0xdeadbeef );
2397 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2398 ok( ret, "failed err %u\n", GetLastError() );
2401 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2404 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2406 /* invalid locale enumerated on some platforms */
2410 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2411 "Enumerated grp %d not valid\n", lgrpid);
2412 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2413 "Enumerated grp locale %d not valid\n", lcid);
2417 static void test_EnumLanguageGroupLocalesA(void)
2421 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2423 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2427 /* No enumeration proc */
2429 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2430 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2432 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2435 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2436 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2438 /* lgrpid too small */
2440 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2441 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2442 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2444 /* lgrpid too big */
2446 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2447 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2448 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2450 /* dwFlags is reserved */
2452 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2453 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2454 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2456 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2459 static void test_SetLocaleInfoA(void)
2462 LCID lcid = GetUserDefaultLCID();
2466 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2467 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2468 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2472 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2473 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2474 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2478 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2479 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2480 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2483 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2485 trace("%s %08lx\n", value, lParam);
2489 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2491 ok(!enumCount, "callback called again unexpected\n");
2496 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2498 ok(0,"callback called unexpected\n");
2502 static void test_EnumUILanguageA(void)
2505 if (!pEnumUILanguagesA) {
2506 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2510 SetLastError(ERROR_SUCCESS);
2511 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2512 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2514 win_skip("EnumUILanguagesA is not implemented\n");
2517 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2520 SetLastError(ERROR_SUCCESS);
2521 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2522 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2524 SetLastError(ERROR_SUCCESS);
2525 ret = pEnumUILanguagesA(NULL, 0, 0);
2526 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2527 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2528 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2530 SetLastError(ERROR_SUCCESS);
2531 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2532 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2533 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2535 SetLastError(ERROR_SUCCESS);
2536 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2537 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2538 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2539 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2542 static char date_fmt_buf[1024];
2544 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2546 lstrcatA(date_fmt_buf, fmt);
2547 lstrcatA(date_fmt_buf, "\n");
2551 static void test_EnumDateFormatsA(void)
2555 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2557 trace("EnumDateFormatsA 0\n");
2558 date_fmt_buf[0] = 0;
2559 SetLastError(0xdeadbeef);
2560 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2561 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2563 win_skip("0 for dwFlags is not supported\n");
2567 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2568 trace("%s\n", date_fmt_buf);
2569 /* test the 1st enumerated format */
2570 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2571 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2572 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2573 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2576 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2577 date_fmt_buf[0] = 0;
2578 SetLastError(0xdeadbeef);
2579 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2580 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2582 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2586 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2587 trace("%s\n", date_fmt_buf);
2588 /* test the 1st enumerated format */
2589 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2590 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2591 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2592 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2595 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2596 date_fmt_buf[0] = 0;
2597 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2598 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2599 trace("%s\n", date_fmt_buf);
2600 /* test the 1st enumerated format */
2601 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2602 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2603 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2604 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2606 trace("EnumDateFormatsA DATE_LONGDATE\n");
2607 date_fmt_buf[0] = 0;
2608 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2609 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2610 trace("%s\n", date_fmt_buf);
2611 /* test the 1st enumerated format */
2612 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2613 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2614 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2615 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2617 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2618 date_fmt_buf[0] = 0;
2619 SetLastError(0xdeadbeef);
2620 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2621 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2623 skip("DATE_YEARMONTH is only present on W2K and later\n");
2626 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2627 trace("%s\n", date_fmt_buf);
2628 /* test the 1st enumerated format */
2629 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2630 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2631 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2632 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2633 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2636 static void test_EnumTimeFormatsA(void)
2640 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2642 trace("EnumTimeFormatsA 0\n");
2643 date_fmt_buf[0] = 0;
2644 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2645 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2646 trace("%s\n", date_fmt_buf);
2647 /* test the 1st enumerated format */
2648 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2649 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2650 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2651 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2653 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2654 date_fmt_buf[0] = 0;
2655 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2656 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2657 trace("%s\n", date_fmt_buf);
2658 /* test the 1st enumerated format */
2659 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2660 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2661 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2662 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2665 static void test_GetCPInfo(void)
2670 SetLastError(0xdeadbeef);
2671 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2672 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2673 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2674 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2676 SetLastError(0xdeadbeef);
2677 ret = GetCPInfo(CP_UTF7, &cpinfo);
2678 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2680 skip("Codepage CP_UTF7 is not installed/available\n");
2684 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2685 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2686 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2687 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2688 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2689 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2692 SetLastError(0xdeadbeef);
2693 ret = GetCPInfo(CP_UTF8, &cpinfo);
2694 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2696 skip("Codepage CP_UTF8 is not installed/available\n");
2700 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2701 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2702 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2703 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2704 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2705 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2706 "expected 4, got %u\n", cpinfo.MaxCharSize);
2711 * The CT_TYPE1 has varied over windows version.
2712 * The current target for correct behavior is windows 7.
2713 * There was a big shift between windows 2000 (first introduced) and windows Xp
2714 * Most of the old values below are from windows 2000.
2715 * A smaller subset of changes happened between windows Xp and Window vista/7
2717 static void test_GetStringTypeW(void)
2719 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2720 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2721 C1_SPACE | C1_BLANK | C1_DEFINED,
2722 C1_SPACE | C1_BLANK | C1_DEFINED,
2723 C1_SPACE | C1_BLANK | C1_DEFINED,
2724 C1_CNTRL | C1_BLANK | C1_DEFINED};
2725 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2726 C1_SPACE | C1_BLANK,
2727 C1_SPACE | C1_BLANK,
2728 C1_SPACE | C1_BLANK,
2729 C1_SPACE | C1_BLANK};
2731 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2734 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2735 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2736 C1_LOWER | C1_ALPHA,
2737 C1_UPPER | C1_LOWER | C1_ALPHA,
2740 /* Sk, Sk, Mn, So, Me */
2741 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2743 0xffe0, 0xffe9, 0x2153};
2745 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2746 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2747 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2748 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2749 C1_ALPHA | C1_DEFINED,
2750 C1_CNTRL | C1_DEFINED,
2751 C1_PUNCT | C1_DEFINED,
2752 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2753 C1_ALPHA | C1_LOWER | C1_DEFINED,
2754 C1_ALPHA | C1_DEFINED };
2755 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2756 C1_ALPHA | C1_DEFINED,
2757 C1_CNTRL | C1_DEFINED,
2758 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2759 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2760 C1_ALPHA | C1_DEFINED,
2763 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2764 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2766 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2767 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2768 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2769 static const WCHAR lower_special[] = {0x2071, 0x207f};
2770 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2771 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2772 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2773 0xfff9, 0xfffa, 0xfffb};
2774 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2779 memset(types,0,sizeof(types));
2780 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2781 for (i = 0; i < 5; i++)
2782 ok(types[i] == blanks_new[i] || broken(types[i] == blanks_old[i] || broken(types[i] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks[i],types[i],blanks_new[i]);
2784 memset(types,0,sizeof(types));
2785 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2786 for (i = 0; i < 3; i++)
2787 ok(types[i] == (C1_DEFINED | alpha_old[i]) || broken(types[i] == alpha_old[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha[i], types[i],(C1_DEFINED | alpha_old[i]));
2788 memset(types,0,sizeof(types));
2789 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2790 for (i = 0; i < 5; i++)
2791 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2793 memset(types,0,sizeof(types));
2794 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2795 for (i = 0; i < 8; i++)
2796 ok(types[i] == C1_DEFINED || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc[i], types[i], C1_DEFINED);
2798 memset(types,0,sizeof(types));
2799 GetStringTypeW(CT_CTYPE1, changed, 7, types);
2800 for (i = 0; i < 7; i++)
2801 ok(types[i] == changed_new[i] || broken(types[i] == changed_old[i]) || broken(types[i] == changed_xp[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed[i], types[i], changed_new[i]);
2803 memset(types,0,sizeof(types));
2804 GetStringTypeW(CT_CTYPE1, punct, 7, types);
2805 for (i = 0; i < 7; i++)
2806 ok(types[i] == (C1_PUNCT | C1_DEFINED) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct[i], types[i], (C1_PUNCT | C1_DEFINED));
2809 memset(types,0,sizeof(types));
2810 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
2811 for (i = 0; i < 12; i++)
2812 ok(types[i] & C1_PUNCT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special[i], types[i], C1_PUNCT);
2814 memset(types,0,sizeof(types));
2815 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
2816 for (i = 0; i < 3; i++)
2817 ok(types[i] & C1_DIGIT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special[i], types[i], C1_DIGIT);
2819 memset(types,0,sizeof(types));
2820 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
2821 for (i = 0; i < 2; i++)
2822 ok(types[i] & C1_LOWER || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special[i], types[i], C1_LOWER);
2824 memset(types,0,sizeof(types));
2825 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
2826 for (i = 0; i < 20; i++)
2827 ok(types[i] & C1_CNTRL || broken(types[i] == (C1_BLANK|C1_SPACE)) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special[i], types[i], C1_CNTRL);
2829 memset(types,0,sizeof(types));
2830 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
2831 for (i = 0; i < 3; i++)
2832 ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
2835 static void test_IdnToNameprepUnicode(void)
2841 const WCHAR out[64];
2847 5, {'t','e','s','t',0},
2848 5, {'t','e','s','t',0},
2852 3, {'a',0xe111,'b'},
2854 0, ERROR_INVALID_NAME
2859 0, ERROR_INVALID_NAME
2869 0, ERROR_INVALID_NAME
2872 6, {' ','-','/','[',']',0},
2873 6, {' ','-','/','[',']',0},
2879 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
2884 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
2886 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
2887 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
2888 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
2892 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
2896 { /* Another example of incorrectly working FoldString (composition) */
2904 0, ERROR_NO_UNICODE_TRANSLATION
2909 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
2912 5, {'a','.','.','a',0},
2914 0, ERROR_INVALID_NAME
2926 if (!pIdnToNameprepUnicode)
2928 win_skip("IdnToNameprepUnicode is not available\n");
2932 ret = pIdnToNameprepUnicode(0, test_data[0].in,
2933 test_data[0].in_len, NULL, 0);
2934 ok(ret == test_data[0].ret, "ret = %d\n", ret);
2936 SetLastError(0xdeadbeef);
2937 ret = pIdnToNameprepUnicode(0, test_data[1].in,
2938 test_data[1].in_len, NULL, 0);
2939 err = GetLastError();
2940 ok(ret == test_data[1].ret, "ret = %d\n", ret);
2941 ok(err == test_data[1].err, "err = %d\n", err);
2943 SetLastError(0xdeadbeef);
2944 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
2945 buf, sizeof(buf)/sizeof(WCHAR));
2946 err = GetLastError();
2947 ok(ret == test_data[0].ret, "ret = %d\n", ret);
2948 ok(err == 0xdeadbeef, "err = %d\n", err);
2950 SetLastError(0xdeadbeef);
2951 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
2952 buf, sizeof(buf)/sizeof(WCHAR));
2953 err = GetLastError();
2954 ok(ret == 0, "ret = %d\n", ret);
2955 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
2957 SetLastError(0xdeadbeef);
2958 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
2959 buf, sizeof(buf)/sizeof(WCHAR));
2960 err = GetLastError();
2961 ok(ret == 0, "ret = %d\n", ret);
2962 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
2964 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
2965 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
2966 ok(ret == test_data[0].ret, "ret = %d\n", ret);
2968 SetLastError(0xdeadbeef);
2969 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
2970 err = GetLastError();
2971 ok(ret == 0, "ret = %d\n", ret);
2972 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
2974 SetLastError(0xdeadbeef);
2975 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
2976 err = GetLastError();
2977 ok(ret == 0, "ret = %d\n", ret);
2978 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
2980 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
2982 SetLastError(0xdeadbeef);
2983 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
2984 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
2985 err = GetLastError();
2986 if(!test_data[i].todo) {
2987 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
2988 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
2989 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
2990 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
2992 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
2993 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
2998 static void test_IdnToAscii(void)
3004 const WCHAR out[64];
3009 5, {'T','e','s','t',0},
3010 5, {'T','e','s','t',0},
3014 5, {'T','e',0x017c,'s','t',0},
3015 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3019 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3020 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3025 9, {'x','n','-','-','2','d','a','.',0},
3029 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3030 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3034 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3035 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3036 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3041 8, {'x','n','-','-','6','l','a',0},
3042 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3051 win_skip("IdnToAscii is not available\n");
3055 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3057 SetLastError(0xdeadbeef);
3058 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3059 test_data[i].in_len, buf, sizeof(buf));
3060 err = GetLastError();
3061 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3062 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3063 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3064 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3068 static void test_IdnToUnicode(void)
3074 const WCHAR out[64];
3079 5, {'T','e','s','.',0},
3080 5, {'T','e','s','.',0},
3086 0, ERROR_INVALID_NAME
3089 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3090 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3091 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3092 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3093 0x05d1,0x05e8,0x05d9,0x05ea,0},
3097 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3098 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3099 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3100 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3104 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3105 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3106 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3107 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3109 0, ERROR_INVALID_NAME
3112 8, {'x','n','-','-','6','l','a',0},
3114 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3123 win_skip("IdnToUnicode is not available\n");
3127 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3129 SetLastError(0xdeadbeef);
3130 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3131 test_data[i].in_len, buf, sizeof(buf));
3132 err = GetLastError();
3133 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3134 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3135 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3136 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3142 InitFunctionPointers();
3144 test_EnumTimeFormatsA();
3145 test_EnumDateFormatsA();
3146 test_GetLocaleInfoA();
3147 test_GetLocaleInfoW();
3148 test_GetTimeFormatA();
3149 test_GetDateFormatA();
3150 test_GetDateFormatW();
3151 test_GetCurrencyFormatA(); /* Also tests the W version */
3152 test_GetNumberFormatA(); /* Also tests the W version */
3153 test_CompareStringA();
3154 test_LCMapStringA();
3155 test_LCMapStringW();
3159 test_ConvertDefaultLocale();
3160 test_EnumSystemLanguageGroupsA();
3161 test_EnumSystemLocalesEx();
3162 test_EnumLanguageGroupLocalesA();
3163 test_SetLocaleInfoA();
3164 test_EnumUILanguageA();
3166 test_GetStringTypeW();
3167 test_IdnToNameprepUnicode();
3169 test_IdnToUnicode();
3170 /* this requires collation table patch to make it MS compatible */
3171 if (0) test_sorting();