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 const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
40 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};
41 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
42 static const WCHAR fooW[] = {'f','o','o',0};
44 static inline unsigned int strlenW( const WCHAR *str )
51 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
54 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
58 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
60 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
64 static inline int isdigitW( WCHAR wc )
67 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
68 return type & C1_DIGIT;
71 /* Some functions are only in later versions of kernel32.dll */
72 static HMODULE hKernel32;
73 static WORD enumCount;
75 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
76 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
77 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
78 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
79 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
80 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
81 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
82 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
83 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
84 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
85 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
86 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
87 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
91 static void InitFunctionPointers(void)
93 hKernel32 = GetModuleHandleA("kernel32");
94 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
95 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
96 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
97 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
98 pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
99 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
100 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
101 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
102 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
103 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
104 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
105 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
106 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
107 pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
108 pIsValidLocaleName = (void*)GetProcAddress(hKernel32, "IsValidLocaleName");
111 #define eq(received, expected, label, type) \
112 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
113 (label), (received), (expected))
115 #define BUFFER_SIZE 128
116 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
118 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
119 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
120 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
121 "Expected '%s', got '%s'\n", Expected, buffer)
123 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
124 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
125 SetLastError(0xdeadbeef); buffer[0] = '\0'
126 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
127 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
129 #define NUO LOCALE_NOUSEROVERRIDE
131 static void test_GetLocaleInfoA(void)
135 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
136 char buffer[BUFFER_SIZE];
137 char expected[BUFFER_SIZE];
140 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
142 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
143 ok(ret, "got %d\n", ret);
144 ok(val == lcid, "got 0x%08x\n", val);
146 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
147 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
148 assumes SUBLANG_NEUTRAL for zh */
149 memset(expected, 0, COUNTOF(expected));
150 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
151 SetLastError(0xdeadbeef);
152 memset(buffer, 0, COUNTOF(buffer));
153 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
154 ok((ret == len) && !lstrcmpA(buffer, expected),
155 "got %d with '%s' (expected %d with '%s')\n",
156 ret, buffer, len, expected);
158 memset(expected, 0, COUNTOF(expected));
159 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
161 SetLastError(0xdeadbeef);
162 memset(buffer, 0, COUNTOF(buffer));
163 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
164 ok((ret == len) && !lstrcmpA(buffer, expected),
165 "got %d with '%s' (expected %d with '%s')\n",
166 ret, buffer, len, expected);
169 win_skip("LANG_ARABIC not installed\n");
171 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
172 memset(expected, 0, COUNTOF(expected));
173 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
174 SetLastError(0xdeadbeef);
175 memset(buffer, 0, COUNTOF(buffer));
176 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
177 ok((ret == len) && !lstrcmpA(buffer, expected),
178 "got %d with '%s' (expected %d with '%s')\n",
179 ret, buffer, len, expected);
182 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
183 * partially fill the buffer even if it is too short. See bug 637.
185 SetLastError(0xdeadbeef);
186 memset(buffer, 0, COUNTOF(buffer));
187 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
188 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
190 SetLastError(0xdeadbeef);
191 memset(buffer, 0, COUNTOF(buffer));
192 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
193 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
194 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
195 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
197 SetLastError(0xdeadbeef);
198 memset(buffer, 0, COUNTOF(buffer));
199 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
200 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
201 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
204 struct neutralsublang_name2_t {
209 WCHAR sname_broken[15];
213 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
214 { {'a','r',0}, {'a','r','-','S','A',0},
215 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
216 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
217 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
218 { {'d','e',0}, {'d','e','-','D','E',0},
219 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
220 { {'e','n',0}, {'e','n','-','U','S',0},
221 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
222 { {'e','s',0}, {'e','s','-','E','S',0},
223 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
224 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
225 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
226 { {'g','a',0}, {'g','a','-','I','E',0},
227 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
228 { {'i','t',0}, {'i','t','-','I','T',0},
229 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
230 { {'m','s',0}, {'m','s','-','M','Y',0},
231 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
232 { {'n','l',0}, {'n','l','-','N','L',0},
233 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
234 { {'p','t',0}, {'p','t','-','B','R',0},
235 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
236 { {'s','r',0}, {'h','r','-','H','R',0},
237 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
238 { {'s','v',0}, {'s','v','-','S','E',0},
239 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
240 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
241 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
242 { {'z','h',0}, {'z','h','-','C','N',0},
243 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
247 static void test_GetLocaleInfoW(void)
249 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
250 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
251 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
252 WCHAR bufferW[80], buffer2W[80];
258 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
260 win_skip("GetLocaleInfoW() isn't implemented\n");
264 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
265 ok(ret, "got %d\n", ret);
266 ok(val == lcid_en, "got 0x%08x\n", val);
268 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
271 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
272 'S','t','a','t','e','s',')',0};
273 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
274 static const WCHAR enW[] = {'e','n','-','U','S',0};
275 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
277 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
279 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
280 ok(ret, "got %d\n", ret);
281 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
283 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
284 ok(ret, "got %d\n", ret);
285 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
292 /* make neutral lcid */
293 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
294 lcid = MAKELCID(langid, SORT_DEFAULT);
297 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
301 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
302 wine_dbgstr_w(ptr->name), val, ptr->lcid);
305 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
306 wine_dbgstr_w(ptr->name), val, ptr->lcid);
308 /* now check LOCALE_SNAME */
309 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
312 ok(!lstrcmpW(bufferW, ptr->sname) ||
313 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
314 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
316 ok(!lstrcmpW(bufferW, ptr->sname) ||
317 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
318 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
323 win_skip("English neutral locale not supported\n");
325 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
327 win_skip("LANG_RUSSIAN locale data unavailable\n");
330 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
331 bufferW, COUNTOF(bufferW));
333 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
337 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
339 SetLastError(0xdeadbeef);
340 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
341 bufferA, COUNTOF(bufferA));
342 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
343 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
344 ok(GetLastError() == ERROR_INVALID_FLAGS,
345 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
348 SetLastError(0xdeadbeef);
349 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
350 bufferW, COUNTOF(bufferW));
352 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
353 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
354 ok(GetLastError() == ERROR_INVALID_FLAGS,
355 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
357 /* yes, test empty 13 month entry too */
358 for (i = 0; i < 12; i++) {
360 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
361 bufferW, COUNTOF(bufferW));
362 ok(ret, "Expected non zero result\n");
363 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
364 ret, lstrlenW(bufferW));
366 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
367 buffer2W, COUNTOF(buffer2W));
368 ok(ret, "Expected non zero result\n");
369 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
370 ret, lstrlenW(buffer2W));
372 ok(lstrcmpW(bufferW, buffer2W) != 0,
373 "Expected genitive name to differ, got the same for month %d\n", i+1);
375 /* for locale without genitive names nominative returned in both cases */
377 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
378 bufferW, COUNTOF(bufferW));
379 ok(ret, "Expected non zero result\n");
380 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
381 ret, lstrlenW(bufferW));
383 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
384 buffer2W, COUNTOF(buffer2W));
385 ok(ret, "Expected non zero result\n");
386 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
387 ret, lstrlenW(buffer2W));
389 ok(lstrcmpW(bufferW, buffer2W) == 0,
390 "Expected same names, got different for month %d\n", i+1);
394 static void test_GetTimeFormatA(void)
398 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
399 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
401 memset(&curtime, 2, sizeof(SYSTEMTIME));
402 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
403 SetLastError(0xdeadbeef);
404 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
405 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
406 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
409 curtime.wMinute = 56;
410 curtime.wSecond = 13;
411 curtime.wMilliseconds = 22;
412 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
413 SetLastError(0xdeadbeef);
414 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
415 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
416 EXPECT_LENA; EXPECT_EQA;
418 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
419 SetLastError(0xdeadbeef);
420 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
421 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
422 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
424 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
425 SetLastError(0xdeadbeef);
426 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
427 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
428 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
430 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
431 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
432 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
435 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
436 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
437 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
438 EXPECT_LENA; EXPECT_EQA;
440 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
441 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
442 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
443 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
444 "Expected '', got '%s'\n", buffer );
446 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
447 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
448 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
449 EXPECT_LENA; EXPECT_EQA;
451 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
452 strcpy(Expected, "8:56 AM");
453 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
454 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
455 EXPECT_LENA; EXPECT_EQA;
457 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
458 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
459 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
460 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
461 "Expected '8.@:56AM', got '%s'\n", buffer );
463 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
464 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
465 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
466 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
467 "Expected '', got '%s'\n", buffer );
469 STRINGSA("t/tt", "A/AM"); /* AM time marker */
470 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
472 EXPECT_LENA; EXPECT_EQA;
475 STRINGSA("t/tt", "P/PM"); /* PM time marker */
476 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
477 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
478 EXPECT_LENA; EXPECT_EQA;
480 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
481 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 EXPECT_LENA; EXPECT_EQA;
485 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
486 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
488 EXPECT_LENA; EXPECT_EQA;
490 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
491 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493 EXPECT_LENA; EXPECT_EQA;
495 curtime.wHour = 14; /* change this to 14 or 2pm */
498 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 */
499 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
500 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
501 EXPECT_LENA; EXPECT_EQA;
504 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
505 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
506 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
507 EXPECT_LENA; EXPECT_EQA;
509 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
510 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
512 EXPECT_LENA; EXPECT_EQA;
514 /* try to convert formatting strings with more than two letters
515 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
516 * NOTE: We expect any letter for which there is an upper case value
517 * we should see a replacement. For letters that DO NOT have
518 * upper case values we should see NO REPLACEMENT.
521 curtime.wMinute = 56;
522 curtime.wSecond = 13;
523 curtime.wMilliseconds = 22;
524 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
525 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
526 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
527 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
528 EXPECT_LENA; EXPECT_EQA;
530 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
531 strcpy(buffer, "text");
532 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
533 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
536 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
537 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
538 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
539 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
540 EXPECT_LENA; EXPECT_EQA;
542 STRINGSA("'''", "'"); /* invalid quoted string */
543 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
545 EXPECT_LENA; EXPECT_EQA;
547 /* test that msdn suggested single quotation usage works as expected */
548 STRINGSA("''''", "'"); /* single quote mark */
549 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
550 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
551 EXPECT_LENA; EXPECT_EQA;
553 STRINGSA("''HHHHHH", "08"); /* Normal use */
554 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
555 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
556 EXPECT_LENA; EXPECT_EQA;
558 /* and test for normal use of the single quotation mark */
559 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
560 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 EXPECT_LENA; EXPECT_EQA;
564 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
565 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
567 EXPECT_LENA; EXPECT_EQA;
569 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
570 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
571 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
572 EXPECT_LENA; EXPECT_EQA;
575 STRINGSA("'123'tt", ""); /* Invalid time */
576 SetLastError(0xdeadbeef);
577 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
579 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
582 curtime.wMonth = 60; /* Invalid */
583 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
584 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
585 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
586 EXPECT_LENA; EXPECT_EQA;
589 static void test_GetDateFormatA(void)
593 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
594 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
595 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
596 char Broken[BUFFER_SIZE];
597 char short_day[10], month[10], genitive_month[10];
599 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
600 STRINGSA("ddd',' MMM dd yy","");
601 SetLastError(0xdeadbeef);
602 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
603 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
604 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
606 curtime.wYear = 2002;
609 curtime.wDayOfWeek = 3;
610 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
611 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
612 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
613 EXPECT_LENA; EXPECT_EQA;
615 /* Same as above but with LOCALE_NOUSEROVERRIDE */
616 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
617 SetLastError(0xdeadbeef);
618 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
619 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
620 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
623 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
624 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
625 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
626 EXPECT_LENA; EXPECT_EQA;
628 curtime.wHour = 36; /* Invalid */
629 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
630 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
631 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
632 EXPECT_LENA; EXPECT_EQA;
634 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
635 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
636 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
639 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
640 SetLastError(0xdeadbeef);
641 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
642 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
643 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
645 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
646 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
647 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
648 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
649 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
651 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
652 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
653 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
654 EXPECT_LENA; EXPECT_EQA;
656 /* test for expected DATE_YEARMONTH behavior with null format */
657 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
658 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
659 SetLastError(0xdeadbeef);
660 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
661 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
662 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
665 /* Test that using invalid DATE_* flags results in the correct error */
666 /* and return values */
667 STRINGSA("m/d/y", ""); /* Invalid flags */
668 SetLastError(0xdeadbeef);
669 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
670 &curtime, input, buffer, COUNTOF(buffer));
671 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
672 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
674 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
677 win_skip("LANG_RUSSIAN locale data unavailable\n");
681 /* month part should be in genitive form */
682 strcpy(genitive_month, buffer + 2);
683 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
684 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
685 strcpy(month, buffer);
686 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
688 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
689 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
690 strcpy(short_day, buffer);
692 STRINGSA("dd MMMMddd dd", "");
693 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
694 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
695 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
698 STRINGSA("MMMMddd dd", "");
699 sprintf(Expected, "%s%s 04", month, short_day);
700 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
704 STRINGSA("MMMMddd", "");
705 sprintf(Expected, "%s%s", month, short_day);
706 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
710 STRINGSA("MMMMdd", "");
711 sprintf(Expected, "%s04", genitive_month);
712 sprintf(Broken, "%s04", month);
713 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
715 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
716 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
717 "Expected '%s', got '%s'\n", Expected, buffer);
719 STRINGSA("MMMMdd ddd", "");
720 sprintf(Expected, "%s04 %s", genitive_month, short_day);
721 sprintf(Broken, "%s04 %s", month, short_day);
722 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
723 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
724 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
725 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
726 "Expected '%s', got '%s'\n", Expected, buffer);
728 STRINGSA("dd dddMMMM", "");
729 sprintf(Expected, "04 %s%s", short_day, month);
730 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
731 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
734 STRINGSA("dd dddMMMM ddd MMMMdd", "");
735 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
736 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
737 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
738 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
739 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
740 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
741 "Expected '%s', got '%s'\n", Expected, buffer);
743 /* with literal part */
744 STRINGSA("ddd',' MMMM dd", "");
745 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
746 sprintf(Broken, "%s, %s 04", short_day, month);
747 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
748 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
749 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
750 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
751 "Expected '%s', got '%s'\n", Expected, buffer);
754 static void test_GetDateFormatW(void)
758 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
759 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
761 STRINGSW("",""); /* If flags is not zero then format must be NULL */
762 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
763 input, buffer, COUNTOF(buffer));
764 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
766 win_skip("GetDateFormatW is not implemented\n");
769 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
770 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
773 STRINGSW("",""); /* NULL buffer, len > 0 */
774 SetLastError(0xdeadbeef);
775 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
776 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
777 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
779 STRINGSW("",""); /* NULL buffer, len == 0 */
780 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
781 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
782 EXPECT_LENW; EXPECT_EQW;
784 curtime.wYear = 2002;
787 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
788 curtime.wHour = 65432; /* Invalid */
789 curtime.wMinute = 34512; /* Invalid */
790 curtime.wSecond = 65535; /* Invalid */
791 curtime.wMilliseconds = 12345;
792 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
793 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
794 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
795 EXPECT_LENW; EXPECT_EQW;
799 curtime.wYear = 1601;
802 curtime.wDayOfWeek = 0; /* Irrelevant */
806 curtime.wMilliseconds = 0;
807 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
808 SetLastError(0xdeadbeef);
809 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
810 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
811 EXPECT_LENW; EXPECT_EQW;
813 curtime.wYear = 1600;
816 curtime.wDayOfWeek = 0; /* Irrelevant */
818 curtime.wMinute = 59;
819 curtime.wSecond = 59;
820 curtime.wMilliseconds = 999;
821 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
822 SetLastError(0xdeadbeef);
823 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
824 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
825 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
829 #define CY_POS_LEFT 0
830 #define CY_POS_RIGHT 1
831 #define CY_POS_LEFT_SPACE 2
832 #define CY_POS_RIGHT_SPACE 3
834 static void test_GetCurrencyFormatA(void)
836 static char szDot[] = { '.', '\0' };
837 static char szComma[] = { ',', '\0' };
838 static char szDollar[] = { '$', '\0' };
840 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
841 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
844 memset(&format, 0, sizeof(format));
846 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
847 SetLastError(0xdeadbeef);
848 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
849 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
850 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
852 STRINGSA("23,53",""); /* Invalid character --> Error */
853 SetLastError(0xdeadbeef);
854 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
855 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
856 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
858 STRINGSA("--",""); /* Double '-' --> Error */
859 SetLastError(0xdeadbeef);
860 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
861 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
862 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
864 STRINGSA("0-",""); /* Trailing '-' --> Error */
865 SetLastError(0xdeadbeef);
866 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
867 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
868 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
870 STRINGSA("0..",""); /* Double '.' --> Error */
871 SetLastError(0xdeadbeef);
872 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
873 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
874 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
876 STRINGSA(" 0.1",""); /* Leading space --> Error */
877 SetLastError(0xdeadbeef);
878 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
879 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
880 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
882 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
883 SetLastError(0xdeadbeef);
884 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
885 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
886 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
888 STRINGSA("2353",""); /* Format and flags given --> Error */
889 SetLastError(0xdeadbeef);
890 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
891 ok( !ret, "Expected ret == 0, got %d\n", ret);
892 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
893 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 STRINGSA("2353",""); /* Invalid format --> Error */
896 SetLastError(0xdeadbeef);
897 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
898 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
899 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
901 STRINGSA("2353","$2,353.00"); /* Valid number */
902 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
903 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
904 EXPECT_LENA; EXPECT_EQA;
906 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
907 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
908 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
909 EXPECT_LENA; EXPECT_EQA;
911 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
912 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
913 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
914 EXPECT_LENA; EXPECT_EQA;
916 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
917 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
918 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919 EXPECT_LENA; EXPECT_EQA;
921 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
922 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
923 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
924 EXPECT_LENA; EXPECT_EQA;
926 format.NumDigits = 0; /* No decimal separator */
927 format.LeadingZero = 0;
928 format.Grouping = 0; /* No grouping char */
929 format.NegativeOrder = 0;
930 format.PositiveOrder = CY_POS_LEFT;
931 format.lpDecimalSep = szDot;
932 format.lpThousandSep = szComma;
933 format.lpCurrencySymbol = szDollar;
935 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
936 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
937 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
938 EXPECT_LENA; EXPECT_EQA;
940 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
941 STRINGSA("2353","$2353.0");
942 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
943 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
944 EXPECT_LENA; EXPECT_EQA;
946 format.Grouping = 2; /* Group by 100's */
947 STRINGSA("2353","$23,53.0");
948 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
949 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
950 EXPECT_LENA; EXPECT_EQA;
952 STRINGSA("235","$235.0"); /* Grouping of a positive number */
954 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
955 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
956 EXPECT_LENA; EXPECT_EQA;
958 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
959 format.NegativeOrder = 2;
960 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
961 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
962 EXPECT_LENA; EXPECT_EQA;
964 format.LeadingZero = 1; /* Always provide leading zero */
965 STRINGSA(".5","$0.5");
966 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
967 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
968 EXPECT_LENA; EXPECT_EQA;
970 format.PositiveOrder = CY_POS_RIGHT;
971 STRINGSA("1","1.0$");
972 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
973 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
974 EXPECT_LENA; EXPECT_EQA;
976 format.PositiveOrder = CY_POS_LEFT_SPACE;
977 STRINGSA("1","$ 1.0");
978 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
979 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
980 EXPECT_LENA; EXPECT_EQA;
982 format.PositiveOrder = CY_POS_RIGHT_SPACE;
983 STRINGSA("1","1.0 $");
984 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
985 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
986 EXPECT_LENA; EXPECT_EQA;
988 format.NegativeOrder = 0;
989 STRINGSA("-1","($1.0)");
990 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
991 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
992 EXPECT_LENA; EXPECT_EQA;
994 format.NegativeOrder = 1;
995 STRINGSA("-1","-$1.0");
996 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
997 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
998 EXPECT_LENA; EXPECT_EQA;
1000 format.NegativeOrder = 2;
1001 STRINGSA("-1","$-1.0");
1002 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1003 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1004 EXPECT_LENA; EXPECT_EQA;
1006 format.NegativeOrder = 3;
1007 STRINGSA("-1","$1.0-");
1008 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1009 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1010 EXPECT_LENA; EXPECT_EQA;
1012 format.NegativeOrder = 4;
1013 STRINGSA("-1","(1.0$)");
1014 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1015 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1016 EXPECT_LENA; EXPECT_EQA;
1018 format.NegativeOrder = 5;
1019 STRINGSA("-1","-1.0$");
1020 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1021 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1022 EXPECT_LENA; EXPECT_EQA;
1024 format.NegativeOrder = 6;
1025 STRINGSA("-1","1.0-$");
1026 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1027 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1028 EXPECT_LENA; EXPECT_EQA;
1030 format.NegativeOrder = 7;
1031 STRINGSA("-1","1.0$-");
1032 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1033 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1034 EXPECT_LENA; EXPECT_EQA;
1036 format.NegativeOrder = 8;
1037 STRINGSA("-1","-1.0 $");
1038 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1039 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1040 EXPECT_LENA; EXPECT_EQA;
1042 format.NegativeOrder = 9;
1043 STRINGSA("-1","-$ 1.0");
1044 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1045 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1046 EXPECT_LENA; EXPECT_EQA;
1048 format.NegativeOrder = 10;
1049 STRINGSA("-1","1.0 $-");
1050 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1051 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1052 EXPECT_LENA; EXPECT_EQA;
1054 format.NegativeOrder = 11;
1055 STRINGSA("-1","$ 1.0-");
1056 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1057 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1058 EXPECT_LENA; EXPECT_EQA;
1060 format.NegativeOrder = 12;
1061 STRINGSA("-1","$ -1.0");
1062 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1063 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064 EXPECT_LENA; EXPECT_EQA;
1066 format.NegativeOrder = 13;
1067 STRINGSA("-1","1.0- $");
1068 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1069 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1070 EXPECT_LENA; EXPECT_EQA;
1072 format.NegativeOrder = 14;
1073 STRINGSA("-1","($ 1.0)");
1074 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1075 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1076 EXPECT_LENA; EXPECT_EQA;
1078 format.NegativeOrder = 15;
1079 STRINGSA("-1","(1.0 $)");
1080 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1081 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1082 EXPECT_LENA; EXPECT_EQA;
1085 #define NEG_PARENS 0 /* "(1.1)" */
1086 #define NEG_LEFT 1 /* "-1.1" */
1087 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1088 #define NEG_RIGHT 3 /* "1.1-" */
1089 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1091 static void test_GetNumberFormatA(void)
1093 static char szDot[] = { '.', '\0' };
1094 static char szComma[] = { ',', '\0' };
1096 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1097 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1100 memset(&format, 0, sizeof(format));
1102 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1103 SetLastError(0xdeadbeef);
1104 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1105 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1106 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1108 STRINGSA("23,53",""); /* Invalid character --> Error */
1109 SetLastError(0xdeadbeef);
1110 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1111 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1112 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1114 STRINGSA("--",""); /* Double '-' --> Error */
1115 SetLastError(0xdeadbeef);
1116 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1117 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1118 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1120 STRINGSA("0-",""); /* Trailing '-' --> Error */
1121 SetLastError(0xdeadbeef);
1122 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1123 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1124 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1126 STRINGSA("0..",""); /* Double '.' --> Error */
1127 SetLastError(0xdeadbeef);
1128 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1129 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1130 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1132 STRINGSA(" 0.1",""); /* Leading space --> Error */
1133 SetLastError(0xdeadbeef);
1134 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1135 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1136 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1138 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1139 SetLastError(0xdeadbeef);
1140 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1141 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1142 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1144 STRINGSA("2353",""); /* Format and flags given --> Error */
1145 SetLastError(0xdeadbeef);
1146 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1147 ok( !ret, "Expected ret == 0, got %d\n", ret);
1148 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1149 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1151 STRINGSA("2353",""); /* Invalid format --> Error */
1152 SetLastError(0xdeadbeef);
1153 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1154 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1155 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1157 STRINGSA("2353","2,353.00"); /* Valid number */
1158 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1159 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1160 EXPECT_LENA; EXPECT_EQA;
1162 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1163 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1164 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1165 EXPECT_LENA; EXPECT_EQA;
1167 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1168 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1169 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1170 EXPECT_LENA; EXPECT_EQA;
1172 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1173 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1174 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1175 EXPECT_LENA; EXPECT_EQA;
1177 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1178 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1179 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1180 EXPECT_LENA; EXPECT_EQA;
1182 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1183 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1184 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1185 EXPECT_LENA; EXPECT_EQA;
1187 format.NumDigits = 0; /* No decimal separator */
1188 format.LeadingZero = 0;
1189 format.Grouping = 0; /* No grouping char */
1190 format.NegativeOrder = 0;
1191 format.lpDecimalSep = szDot;
1192 format.lpThousandSep = szComma;
1194 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1195 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1196 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1197 EXPECT_LENA; EXPECT_EQA;
1199 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1200 STRINGSA("2353","2353.0");
1201 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1202 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1203 EXPECT_LENA; EXPECT_EQA;
1205 format.Grouping = 2; /* Group by 100's */
1206 STRINGSA("2353","23,53.0");
1207 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1208 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1209 EXPECT_LENA; EXPECT_EQA;
1211 STRINGSA("235","235.0"); /* Grouping of a positive number */
1212 format.Grouping = 3;
1213 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1214 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1215 EXPECT_LENA; EXPECT_EQA;
1217 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1218 format.NegativeOrder = NEG_LEFT;
1219 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1220 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1221 EXPECT_LENA; EXPECT_EQA;
1223 format.LeadingZero = 1; /* Always provide leading zero */
1224 STRINGSA(".5","0.5");
1225 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1226 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1227 EXPECT_LENA; EXPECT_EQA;
1229 format.NegativeOrder = NEG_PARENS;
1230 STRINGSA("-1","(1.0)");
1231 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1232 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1233 EXPECT_LENA; EXPECT_EQA;
1235 format.NegativeOrder = NEG_LEFT;
1236 STRINGSA("-1","-1.0");
1237 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1238 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1239 EXPECT_LENA; EXPECT_EQA;
1241 format.NegativeOrder = NEG_LEFT_SPACE;
1242 STRINGSA("-1","- 1.0");
1243 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1244 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1245 EXPECT_LENA; EXPECT_EQA;
1247 format.NegativeOrder = NEG_RIGHT;
1248 STRINGSA("-1","1.0-");
1249 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1250 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1251 EXPECT_LENA; EXPECT_EQA;
1253 format.NegativeOrder = NEG_RIGHT_SPACE;
1254 STRINGSA("-1","1.0 -");
1255 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1256 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1257 EXPECT_LENA; EXPECT_EQA;
1259 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1261 if (IsValidLocale(lcid, 0))
1263 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1264 Expected[3] = 160; /* Non breaking space */
1265 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1266 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1267 EXPECT_LENA; EXPECT_EQA;
1271 struct comparestringa_entry {
1281 static const struct comparestringa_entry comparestringa_data[] = {
1282 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1283 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1284 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1285 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1286 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1287 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1288 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1289 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1290 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1291 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1292 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1293 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1294 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1295 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1296 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1297 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1298 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1299 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1300 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1301 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1302 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1303 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1304 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1305 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1306 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1307 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1308 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1309 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1310 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1311 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1314 static void test_CompareStringA(void)
1317 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1319 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1321 const struct comparestringa_entry *entry = &comparestringa_data[i];
1323 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1324 entry->second, entry->second_len);
1325 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1328 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1329 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1331 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1332 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1334 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1335 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1337 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1338 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1340 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1342 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1343 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1345 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1346 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1348 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1349 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1351 /* test for CompareStringA flags */
1352 SetLastError(0xdeadbeef);
1353 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1354 ok(GetLastError() == ERROR_INVALID_FLAGS,
1355 "unexpected error code %d\n", GetLastError());
1356 ok(!ret, "CompareStringA must fail with invalid flag\n");
1358 SetLastError(0xdeadbeef);
1359 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1360 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1361 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1362 /* end of test for CompareStringA flags */
1364 ret = lstrcmpA("", "");
1365 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1367 ret = lstrcmpA(NULL, NULL);
1368 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1370 ret = lstrcmpA("", NULL);
1371 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1373 ret = lstrcmpA(NULL, "");
1374 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1377 if (0) { /* this requires collation table patch to make it MS compatible */
1378 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1379 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1381 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1382 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1384 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1385 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1387 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1388 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1390 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1391 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1393 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1394 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1396 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1397 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1399 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1400 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1402 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1403 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1405 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1406 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1408 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1409 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1411 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1412 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1416 /* WinXP handles embedded NULLs differently than earlier versions */
1417 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1418 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1420 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1421 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1423 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1424 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1426 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1427 ok(ret == CSTR_EQUAL || /* win2k */
1428 ret == CSTR_GREATER_THAN,
1429 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1431 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1432 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1434 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1435 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1437 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1438 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1440 ret = lstrcmpi("#", ".");
1441 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1443 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1445 /* \xB9 character lies between a and b */
1446 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1447 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1448 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1449 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1452 static void test_LCMapStringA(void)
1455 char buf[256], buf2[256];
1456 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1457 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1458 static const char symbols_stripped[] = "justateststring1";
1460 SetLastError(0xdeadbeef);
1461 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1462 lower_case, -1, buf, sizeof(buf));
1463 ok(ret == lstrlenA(lower_case) + 1,
1464 "ret %d, error %d, expected value %d\n",
1465 ret, GetLastError(), lstrlenA(lower_case) + 1);
1466 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1468 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1469 upper_case, -1, buf, sizeof(buf));
1470 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1471 ok(GetLastError() == ERROR_INVALID_FLAGS,
1472 "unexpected error code %d\n", GetLastError());
1474 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1475 upper_case, -1, buf, sizeof(buf));
1476 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1477 ok(GetLastError() == ERROR_INVALID_FLAGS,
1478 "unexpected error code %d\n", GetLastError());
1480 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1481 upper_case, -1, buf, sizeof(buf));
1482 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1483 ok(GetLastError() == ERROR_INVALID_FLAGS,
1484 "unexpected error code %d\n", GetLastError());
1486 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1487 upper_case, -1, buf, sizeof(buf));
1488 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1489 ok(GetLastError() == ERROR_INVALID_FLAGS,
1490 "unexpected error code %d\n", GetLastError());
1492 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1493 SetLastError(0xdeadbeef);
1494 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1495 upper_case, -1, buf, sizeof(buf));
1496 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1497 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1499 /* test LCMAP_LOWERCASE */
1500 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1501 upper_case, -1, buf, sizeof(buf));
1502 ok(ret == lstrlenA(upper_case) + 1,
1503 "ret %d, error %d, expected value %d\n",
1504 ret, GetLastError(), lstrlenA(upper_case) + 1);
1505 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1507 /* test LCMAP_UPPERCASE */
1508 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1509 lower_case, -1, buf, sizeof(buf));
1510 ok(ret == lstrlenA(lower_case) + 1,
1511 "ret %d, error %d, expected value %d\n",
1512 ret, GetLastError(), lstrlenA(lower_case) + 1);
1513 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1515 /* test buffer overflow */
1516 SetLastError(0xdeadbeef);
1517 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1518 lower_case, -1, buf, 4);
1519 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1520 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1522 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1523 lstrcpyA(buf, lower_case);
1524 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1525 buf, -1, buf, sizeof(buf));
1526 if (!ret) /* Win9x */
1527 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1530 ok(ret == lstrlenA(lower_case) + 1,
1531 "ret %d, error %d, expected value %d\n",
1532 ret, GetLastError(), lstrlenA(lower_case) + 1);
1533 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1535 lstrcpyA(buf, upper_case);
1536 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1537 buf, -1, buf, sizeof(buf));
1538 if (!ret) /* Win9x */
1539 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1542 ok(ret == lstrlenA(upper_case) + 1,
1543 "ret %d, error %d, expected value %d\n",
1544 ret, GetLastError(), lstrlenA(lower_case) + 1);
1545 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1548 /* otherwise src == dst should fail */
1549 SetLastError(0xdeadbeef);
1550 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1551 buf, 10, buf, sizeof(buf));
1552 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1553 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1554 "unexpected error code %d\n", GetLastError());
1555 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1557 /* test whether '\0' is always appended */
1558 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1559 upper_case, -1, buf, sizeof(buf));
1560 ok(ret, "LCMapStringA must succeed\n");
1561 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1562 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1563 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1564 ok(ret2, "LCMapStringA must succeed\n");
1565 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1566 ok(ret == ret2, "lengths of sort keys must be equal\n");
1567 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1569 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1570 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1571 upper_case, -1, buf, sizeof(buf));
1572 ok(ret, "LCMapStringA must succeed\n");
1573 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1574 lower_case, -1, buf2, sizeof(buf2));
1575 ok(ret2, "LCMapStringA must succeed\n");
1576 ok(ret == ret2, "lengths of sort keys must be equal\n");
1577 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1579 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1580 results from plain LCMAP_SORTKEY on Vista */
1582 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1583 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1584 lower_case, -1, buf, sizeof(buf));
1585 ok(ret, "LCMapStringA must succeed\n");
1586 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1587 symbols_stripped, -1, buf2, sizeof(buf2));
1588 ok(ret2, "LCMapStringA must succeed\n");
1589 ok(ret == ret2, "lengths of sort keys must be equal\n");
1590 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1592 /* test NORM_IGNORENONSPACE */
1593 lstrcpyA(buf, "foo");
1594 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1595 lower_case, -1, buf, sizeof(buf));
1596 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1597 lstrlenA(lower_case) + 1, ret);
1598 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1600 /* test NORM_IGNORESYMBOLS */
1601 lstrcpyA(buf, "foo");
1602 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1603 lower_case, -1, buf, sizeof(buf));
1604 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1605 lstrlenA(symbols_stripped) + 1, ret);
1606 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1608 /* test srclen = 0 */
1609 SetLastError(0xdeadbeef);
1610 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1611 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1612 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1613 "unexpected error code %d\n", GetLastError());
1616 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1618 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1621 WCHAR buf[256], buf2[256];
1622 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1624 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1625 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1627 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1630 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1631 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1632 func_name, GetLastError());
1635 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1636 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1637 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1638 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1639 func_name, GetLastError());
1641 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1642 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1643 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1644 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1645 func_name, GetLastError());
1647 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1648 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1649 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1651 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1652 func_name, GetLastError());
1654 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1655 SetLastError(0xdeadbeef);
1656 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1657 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1658 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1659 func_name, GetLastError());
1660 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1662 /* test LCMAP_LOWERCASE */
1663 ret = func_ptr(LCMAP_LOWERCASE,
1664 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1665 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1666 ret, GetLastError(), lstrlenW(upper_case) + 1);
1667 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1669 /* test LCMAP_UPPERCASE */
1670 ret = func_ptr(LCMAP_UPPERCASE,
1671 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1672 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1673 ret, GetLastError(), lstrlenW(lower_case) + 1);
1674 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1676 /* test buffer overflow */
1677 SetLastError(0xdeadbeef);
1678 ret = func_ptr(LCMAP_UPPERCASE,
1679 lower_case, -1, buf, 4);
1680 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1681 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1683 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1684 lstrcpyW(buf, lower_case);
1685 ret = func_ptr(LCMAP_UPPERCASE,
1686 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1687 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1688 ret, GetLastError(), lstrlenW(lower_case) + 1);
1689 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1691 lstrcpyW(buf, upper_case);
1692 ret = func_ptr(LCMAP_LOWERCASE,
1693 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1694 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1695 ret, GetLastError(), lstrlenW(lower_case) + 1);
1696 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1698 /* otherwise src == dst should fail */
1699 SetLastError(0xdeadbeef);
1700 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1701 buf, 10, buf, sizeof(buf));
1702 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1703 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1704 "%s unexpected error code %d\n", func_name, GetLastError());
1705 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1707 /* test whether '\0' is always appended */
1708 ret = func_ptr(LCMAP_SORTKEY,
1709 upper_case, -1, buf, sizeof(buf));
1710 ok(ret, "%s func_ptr must succeed\n", func_name);
1711 ret2 = func_ptr(LCMAP_SORTKEY,
1712 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1713 ok(ret, "%s func_ptr must succeed\n", func_name);
1714 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1715 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1717 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1718 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1719 upper_case, -1, buf, sizeof(buf));
1720 ok(ret, "%s func_ptr must succeed\n", func_name);
1721 ret2 = func_ptr(LCMAP_SORTKEY,
1722 lower_case, -1, buf2, sizeof(buf2));
1723 ok(ret2, "%s func_ptr must succeed\n", func_name);
1724 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1725 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1727 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1728 results from plain LCMAP_SORTKEY on Vista */
1730 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1731 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1732 lower_case, -1, buf, sizeof(buf));
1733 ok(ret, "%s func_ptr must succeed\n", func_name);
1734 ret2 = func_ptr(LCMAP_SORTKEY,
1735 symbols_stripped, -1, buf2, sizeof(buf2));
1736 ok(ret2, "%s func_ptr must succeed\n", func_name);
1737 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1738 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1740 /* test NORM_IGNORENONSPACE */
1741 lstrcpyW(buf, fooW);
1742 ret = func_ptr(NORM_IGNORENONSPACE,
1743 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1744 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1745 lstrlenW(lower_case) + 1, ret);
1746 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1748 /* test NORM_IGNORESYMBOLS */
1749 lstrcpyW(buf, fooW);
1750 ret = func_ptr(NORM_IGNORESYMBOLS,
1751 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1752 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1753 lstrlenW(symbols_stripped) + 1, ret);
1754 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1756 /* test srclen = 0 */
1757 SetLastError(0xdeadbeef);
1758 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1759 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1761 "%s unexpected error code %d\n", func_name, GetLastError());
1764 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1766 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1769 static void test_LCMapStringW(void)
1774 trace("testing LCMapStringW\n");
1776 SetLastError(0xdeadbeef);
1777 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1779 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1780 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1783 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1786 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1788 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1791 static void test_LCMapStringEx(void)
1796 if (!pLCMapStringEx)
1798 win_skip( "LCMapStringEx not available\n" );
1802 trace("testing LCMapStringEx\n");
1804 SetLastError(0xdeadbeef);
1805 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
1806 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1808 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1809 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1812 /* test reserved parameters */
1813 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1814 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1815 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1816 ret, GetLastError(), lstrlenW(upper_case) + 1);
1817 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1819 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1820 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1821 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1822 ret, GetLastError(), lstrlenW(upper_case) + 1);
1823 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1825 /* crashes on native */
1827 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1828 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1830 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1833 struct neutralsublang_name_t {
1839 static const struct neutralsublang_name_t neutralsublang_names[] = {
1840 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1841 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1842 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1843 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1844 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1845 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1846 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1847 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1848 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1849 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1850 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1851 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1852 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1853 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1857 static void test_LocaleNameToLCID(void)
1861 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1862 static const WCHAR enW[] = {'e','n',0};
1864 if (!pLocaleNameToLCID)
1866 win_skip( "LocaleNameToLCID not available\n" );
1872 SetLastError(0xdeadbeef);
1873 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1874 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1875 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
1876 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1877 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1878 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1881 SetLastError(0xdeadbeef);
1882 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1883 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1884 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
1885 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1886 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1887 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1890 SetLastError(0xdeadbeef);
1891 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1892 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1893 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1894 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1895 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1898 SetLastError(0xdeadbeef);
1899 lcid = pLocaleNameToLCID(fooW, 0);
1900 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1901 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
1903 /* english neutral name */
1904 lcid = pLocaleNameToLCID(enW, 0);
1905 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1906 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1909 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1913 lcid = pLocaleNameToLCID(ptr->name, 0);
1916 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1917 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1919 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1920 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1926 /* this requires collation table patch to make it MS compatible */
1927 static const char * const strings_sorted[] =
1959 static const char * const strings[] =
1991 static int compare_string1(const void *e1, const void *e2)
1993 const char *s1 = *(const char *const *)e1;
1994 const char *s2 = *(const char *const *)e2;
1996 return lstrcmpA(s1, s2);
1999 static int compare_string2(const void *e1, const void *e2)
2001 const char *s1 = *(const char *const *)e1;
2002 const char *s2 = *(const char *const *)e2;
2004 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2007 static int compare_string3(const void *e1, const void *e2)
2009 const char *s1 = *(const char *const *)e1;
2010 const char *s2 = *(const char *const *)e2;
2011 char key1[256], key2[256];
2013 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2014 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2015 return strcmp(key1, key2);
2018 static void test_sorting(void)
2021 char **str_buf = (char **)buf;
2024 assert(sizeof(buf) >= sizeof(strings));
2026 /* 1. sort using lstrcmpA */
2027 memcpy(buf, strings, sizeof(strings));
2028 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2029 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2031 ok(!strcmp(strings_sorted[i], str_buf[i]),
2032 "qsort using lstrcmpA failed for element %d\n", i);
2034 /* 2. sort using CompareStringA */
2035 memcpy(buf, strings, sizeof(strings));
2036 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2037 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2039 ok(!strcmp(strings_sorted[i], str_buf[i]),
2040 "qsort using CompareStringA failed for element %d\n", i);
2042 /* 3. sort using sort keys */
2043 memcpy(buf, strings, sizeof(strings));
2044 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2045 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2047 ok(!strcmp(strings_sorted[i], str_buf[i]),
2048 "qsort using sort keys failed for element %d\n", i);
2052 static void test_FoldStringA(void)
2056 char src[256], dst[256];
2057 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2058 static const char digits_dst[] = { '1','2','3','\0' };
2059 static const char composite_src[] =
2061 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2062 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2063 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2064 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2065 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2066 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2067 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2068 0xfb,0xfc,0xfd,0xff,'\0'
2070 static const char composite_dst[] =
2072 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2073 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2074 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2075 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2076 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2077 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2078 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2079 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2080 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2081 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2082 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2083 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2084 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2085 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2086 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2088 static const char composite_dst_alt[] =
2090 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2091 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2092 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2093 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2094 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2095 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2096 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2097 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2098 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2099 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2100 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2101 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2102 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2103 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2104 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2106 static const char ligatures_src[] =
2108 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2110 static const char ligatures_dst[] =
2112 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2114 static const struct special
2118 } foldczone_special[] =
2121 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2122 { 0x98, { 0x20, 0x7e, 0x00 } },
2123 { 0x99, { 0x54, 0x4d, 0x00 } },
2124 { 0xa0, { 0x20, 0x00 } },
2125 { 0xa8, { 0x20, 0xa8, 0x00 } },
2126 { 0xaa, { 0x61, 0x00 } },
2127 { 0xaf, { 0x20, 0xaf, 0x00 } },
2128 { 0xb2, { 0x32, 0x00 } },
2129 { 0xb3, { 0x33, 0x00 } },
2130 { 0xb4, { 0x20, 0xb4, 0x00 } },
2131 { 0xb8, { 0x20, 0xb8, 0x00 } },
2132 { 0xb9, { 0x31, 0x00 } },
2133 { 0xba, { 0x6f, 0x00 } },
2134 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2135 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2136 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2141 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2143 /* these tests are locale specific */
2144 if (GetACP() != 1252)
2146 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2150 /* MAP_FOLDDIGITS */
2152 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2153 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2155 win_skip("FoldStringA is not implemented\n");
2158 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2159 ok(strcmp(dst, digits_dst) == 0,
2160 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2161 for (i = 1; i < 256; i++)
2163 if (!strchr(digits_src, i))
2168 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2169 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2170 ok(dst[0] == src[0],
2171 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2175 /* MAP_EXPAND_LIGATURES */
2177 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2178 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2179 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2180 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2181 ok(strcmp(dst, ligatures_dst) == 0,
2182 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2183 for (i = 1; i < 256; i++)
2185 if (!strchr(ligatures_src, i))
2190 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2194 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2195 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2196 "Got %s for %d\n", dst, i);
2200 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2201 ok(dst[0] == src[0],
2202 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2210 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2211 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2212 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2213 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2214 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2216 for (i = 1; i < 256; i++)
2218 if (!strchr(composite_src, i))
2223 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2224 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2225 ok(dst[0] == src[0],
2226 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2227 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2232 for (i = 1; i < 256; i++)
2237 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2239 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2241 if (foldczone_special[j].src == src[0])
2243 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2244 "Expected ret == 2 or %d, got %d, error %d\n",
2245 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2246 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2247 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2248 (unsigned char)src[0]);
2254 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2255 ok(src[0] == dst[0],
2256 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2257 (unsigned char)src[0], (unsigned char)dst[0]);
2261 /* MAP_PRECOMPOSED */
2262 for (i = 1; i < 256; i++)
2267 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2268 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2269 ok(src[0] == dst[0],
2270 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2271 (unsigned char)src[0], (unsigned char)dst[0]);
2275 static void test_FoldStringW(void)
2279 WCHAR src[256], dst[256], ch, prev_ch = 1;
2280 static const DWORD badFlags[] =
2283 MAP_PRECOMPOSED|MAP_COMPOSITE,
2284 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2285 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2287 /* Ranges of digits 0-9 : Must be sorted! */
2288 static const WCHAR digitRanges[] =
2290 0x0030, /* '0'-'9' */
2291 0x0660, /* Eastern Arabic */
2292 0x06F0, /* Arabic - Hindu */
2293 0x0966, /* Devengari */
2294 0x09E6, /* Bengalii */
2295 0x0A66, /* Gurmukhi */
2296 0x0AE6, /* Gujarati */
2298 0x0BE6, /* Tamil - No 0 */
2299 0x0C66, /* Telugu */
2300 0x0CE6, /* Kannada */
2301 0x0D66, /* Maylayalam */
2304 0x0F29, /* Tibet - 0 is out of sequence */
2305 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2306 0x2080, /* Subscript */
2307 0x245F, /* Circled - 0 is out of sequence */
2308 0x2473, /* Bracketed */
2309 0x2487, /* Full stop */
2310 0x2775, /* Inverted circled - No 0 */
2311 0x277F, /* Patterned circled - No 0 */
2312 0x2789, /* Inverted Patterned circled - No 0 */
2313 0x3020, /* Hangzhou */
2314 0xff10, /* Pliene chasse (?) */
2315 0xffff /* Terminator */
2317 /* Digits which are represented, but out of sequence */
2318 static const WCHAR outOfSequenceDigits[] =
2320 0xB9, /* Superscript 1 */
2321 0xB2, /* Superscript 2 */
2322 0xB3, /* Superscript 3 */
2323 0x0F33, /* Tibetan half zero */
2324 0x24EA, /* Circled 0 */
2325 0x3007, /* Ideographic number zero */
2326 '\0' /* Terminator */
2328 /* Digits in digitRanges for which no representation is available */
2329 static const WCHAR noDigitAvailable[] =
2331 0x0BE6, /* No Tamil 0 */
2332 0x0F29, /* No Tibetan half zero (out of sequence) */
2333 0x2473, /* No Bracketed 0 */
2334 0x2487, /* No 0 Full stop */
2335 0x2775, /* No inverted circled 0 */
2336 0x277F, /* No patterned circled */
2337 0x2789, /* No inverted Patterned circled */
2338 0x3020, /* No Hangzhou 0 */
2339 '\0' /* Terminator */
2341 static const WCHAR foldczone_src[] =
2343 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2344 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2346 static const WCHAR foldczone_dst[] =
2348 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2350 static const WCHAR foldczone_todo_src[] =
2352 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2354 static const WCHAR foldczone_todo_dst[] =
2356 0x3cb,0x1f0,' ','a',0
2358 static const WCHAR foldczone_todo_broken_dst[] =
2360 0x3cb,0x1f0,0xa0,0xaa,0
2362 static const WCHAR ligatures_src[] =
2364 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2365 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2366 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2367 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2368 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2369 0xfb04, 0xfb05, 0xfb06, '\0'
2371 static const WCHAR ligatures_dst[] =
2373 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2374 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2375 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2376 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2377 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2378 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2383 win_skip("FoldStringW is not available\n");
2384 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2387 /* Invalid flag combinations */
2388 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2390 src[0] = dst[0] = '\0';
2392 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2393 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2395 win_skip("FoldStringW is not implemented\n");
2398 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2399 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2402 /* src & dst cannot be the same */
2404 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2405 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2406 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2408 /* src can't be NULL */
2410 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2411 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2412 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2414 /* srclen can't be 0 */
2416 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2417 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2418 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2420 /* dstlen can't be < 0 */
2422 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2423 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2424 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2426 /* Ret includes terminating NUL which is appended if srclen = -1 */
2431 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2432 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2433 ok(dst[0] == 'A' && dst[1] == '\0',
2434 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2435 'A', '\0', ret, dst[0], dst[1], GetLastError());
2437 /* If size is given, result is not NUL terminated */
2443 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2444 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2445 ok(dst[0] == 'A' && dst[1] == 'X',
2446 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2447 'A','X', ret, dst[0], dst[1], GetLastError());
2449 /* MAP_FOLDDIGITS */
2450 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2452 /* Check everything before this range */
2453 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2457 src[1] = dst[0] = '\0';
2458 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2459 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2461 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2462 /* Wine (correctly) maps all Unicode 4.0+ digits */
2463 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2464 (ch >= 0x1369 && ch <= 0x1371),
2465 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2468 if (digitRanges[j] == 0xffff)
2469 break; /* Finished the whole code point space */
2471 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2475 /* Map out of sequence characters */
2476 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2477 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2478 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2479 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2483 src[1] = dst[0] = '\0';
2484 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2485 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2487 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2488 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2489 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2490 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2491 strchrW(noDigitAvailable, c),
2492 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2493 ch, '0' + digitRanges[j] - ch, dst[0]);
2500 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2501 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2502 "Got %d, error %d\n", ret, GetLastError());
2503 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2504 "MAP_FOLDCZONE: Expanded incorrectly\n");
2506 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2507 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2508 "Got %d, error %d\n", ret, GetLastError());
2509 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2510 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2511 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2513 /* MAP_EXPAND_LIGATURES */
2515 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2516 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2517 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2518 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2519 "Got %d, error %d\n", ret, GetLastError());
2520 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2521 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2524 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2529 #define LCID_OK(l) \
2530 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2531 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2532 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2533 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2534 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2536 static void test_ConvertDefaultLocale(void)
2540 /* Doesn't change lcid, even if non default sublang/sort used */
2541 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2542 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2543 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2544 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2546 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2547 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2548 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2549 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2550 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2552 /* Invariant language is not treated specially */
2553 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2555 /* User/system default languages alone are not mapped */
2556 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2557 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2560 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2561 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2562 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2565 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2566 DWORD dwFlags, LONG_PTR lParam)
2568 trace("%08x, %s, %s, %08x, %08lx\n",
2569 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2571 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2572 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2574 /* If lParam is one, we are calling with flags defaulted from 0 */
2575 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2576 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2581 static void test_EnumSystemLanguageGroupsA(void)
2585 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2587 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2591 /* No enumeration proc */
2593 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2594 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2596 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2599 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2600 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2604 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2605 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2607 /* No flags - defaults to LGRPID_INSTALLED */
2608 SetLastError(0xdeadbeef);
2609 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2610 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2612 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2613 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2616 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2618 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2622 static void test_EnumSystemLocalesEx(void)
2626 if (!pEnumSystemLocalesEx)
2628 win_skip( "EnumSystemLocalesEx not available\n" );
2631 SetLastError( 0xdeadbeef );
2632 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2633 ok( !ret, "should have failed\n" );
2634 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2635 SetLastError( 0xdeadbeef );
2636 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2637 ok( ret, "failed err %u\n", GetLastError() );
2640 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2643 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2645 /* invalid locale enumerated on some platforms */
2649 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2650 "Enumerated grp %d not valid\n", lgrpid);
2651 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2652 "Enumerated grp locale %d not valid\n", lcid);
2656 static void test_EnumLanguageGroupLocalesA(void)
2660 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2662 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2666 /* No enumeration proc */
2668 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2669 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2671 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2674 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2675 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2677 /* lgrpid too small */
2679 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2680 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2681 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2683 /* lgrpid too big */
2685 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2686 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2687 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2689 /* dwFlags is reserved */
2691 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2692 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2693 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2695 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2698 static void test_SetLocaleInfoA(void)
2701 LCID lcid = GetUserDefaultLCID();
2705 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2706 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2707 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2711 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2712 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2713 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2717 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2718 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2719 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2722 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2724 trace("%s %08lx\n", value, lParam);
2728 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2730 ok(!enumCount, "callback called again unexpected\n");
2735 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2737 ok(0,"callback called unexpected\n");
2741 static void test_EnumUILanguageA(void)
2744 if (!pEnumUILanguagesA) {
2745 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2749 SetLastError(ERROR_SUCCESS);
2750 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2751 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2753 win_skip("EnumUILanguagesA is not implemented\n");
2756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2759 SetLastError(ERROR_SUCCESS);
2760 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2761 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2763 SetLastError(ERROR_SUCCESS);
2764 ret = pEnumUILanguagesA(NULL, 0, 0);
2765 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2766 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2767 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2769 SetLastError(ERROR_SUCCESS);
2770 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2771 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2772 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2774 SetLastError(ERROR_SUCCESS);
2775 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2776 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2777 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2778 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2781 static char date_fmt_buf[1024];
2783 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2785 lstrcatA(date_fmt_buf, fmt);
2786 lstrcatA(date_fmt_buf, "\n");
2790 static void test_EnumDateFormatsA(void)
2794 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2796 trace("EnumDateFormatsA 0\n");
2797 date_fmt_buf[0] = 0;
2798 SetLastError(0xdeadbeef);
2799 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2800 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2802 win_skip("0 for dwFlags is not supported\n");
2806 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2807 trace("%s\n", date_fmt_buf);
2808 /* test the 1st enumerated format */
2809 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2810 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2811 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2812 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2815 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2816 date_fmt_buf[0] = 0;
2817 SetLastError(0xdeadbeef);
2818 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2819 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2821 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2825 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2826 trace("%s\n", date_fmt_buf);
2827 /* test the 1st enumerated format */
2828 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2829 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2830 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2831 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2834 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2835 date_fmt_buf[0] = 0;
2836 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2837 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2838 trace("%s\n", date_fmt_buf);
2839 /* test the 1st enumerated format */
2840 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2841 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2842 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2843 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2845 trace("EnumDateFormatsA DATE_LONGDATE\n");
2846 date_fmt_buf[0] = 0;
2847 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2848 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2849 trace("%s\n", date_fmt_buf);
2850 /* test the 1st enumerated format */
2851 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2852 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2853 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2854 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2856 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2857 date_fmt_buf[0] = 0;
2858 SetLastError(0xdeadbeef);
2859 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2860 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2862 skip("DATE_YEARMONTH is only present on W2K and later\n");
2865 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2866 trace("%s\n", date_fmt_buf);
2867 /* test the 1st enumerated format */
2868 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2869 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2870 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2871 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2872 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2875 static void test_EnumTimeFormatsA(void)
2879 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2881 trace("EnumTimeFormatsA 0\n");
2882 date_fmt_buf[0] = 0;
2883 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2884 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2885 trace("%s\n", date_fmt_buf);
2886 /* test the 1st enumerated format */
2887 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2888 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2889 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2890 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2892 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2893 date_fmt_buf[0] = 0;
2894 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2895 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2896 trace("%s\n", date_fmt_buf);
2897 /* test the 1st enumerated format */
2898 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2899 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2900 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2901 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2904 static void test_GetCPInfo(void)
2909 SetLastError(0xdeadbeef);
2910 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2911 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2912 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2913 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2915 SetLastError(0xdeadbeef);
2916 ret = GetCPInfo(CP_UTF7, &cpinfo);
2917 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2919 skip("Codepage CP_UTF7 is not installed/available\n");
2923 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2924 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2925 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2926 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2927 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2928 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2931 SetLastError(0xdeadbeef);
2932 ret = GetCPInfo(CP_UTF8, &cpinfo);
2933 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2935 skip("Codepage CP_UTF8 is not installed/available\n");
2939 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2940 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2941 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2942 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2943 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2944 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2945 "expected 4, got %u\n", cpinfo.MaxCharSize);
2950 * The CT_TYPE1 has varied over windows version.
2951 * The current target for correct behavior is windows 7.
2952 * There was a big shift between windows 2000 (first introduced) and windows Xp
2953 * Most of the old values below are from windows 2000.
2954 * A smaller subset of changes happened between windows Xp and Window vista/7
2956 static void test_GetStringTypeW(void)
2958 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2959 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2960 C1_SPACE | C1_BLANK | C1_DEFINED,
2961 C1_SPACE | C1_BLANK | C1_DEFINED,
2962 C1_SPACE | C1_BLANK | C1_DEFINED,
2963 C1_CNTRL | C1_BLANK | C1_DEFINED};
2964 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2965 C1_SPACE | C1_BLANK,
2966 C1_SPACE | C1_BLANK,
2967 C1_SPACE | C1_BLANK,
2968 C1_SPACE | C1_BLANK};
2970 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2973 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2974 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2975 C1_LOWER | C1_ALPHA,
2976 C1_UPPER | C1_LOWER | C1_ALPHA,
2979 /* Sk, Sk, Mn, So, Me */
2980 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2982 0xffe0, 0xffe9, 0x2153};
2984 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2985 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2986 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2987 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2988 C1_ALPHA | C1_DEFINED,
2989 C1_CNTRL | C1_DEFINED,
2990 C1_PUNCT | C1_DEFINED,
2991 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2992 C1_ALPHA | C1_LOWER | C1_DEFINED,
2993 C1_ALPHA | C1_DEFINED };
2994 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2995 C1_ALPHA | C1_DEFINED,
2996 C1_CNTRL | C1_DEFINED,
2997 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2998 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2999 C1_ALPHA | C1_DEFINED,
3002 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3003 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3005 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3006 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3007 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3008 static const WCHAR lower_special[] = {0x2071, 0x207f};
3009 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3010 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3011 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3012 0xfff9, 0xfffa, 0xfffb};
3013 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3018 memset(types,0,sizeof(types));
3019 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3020 for (i = 0; i < 5; i++)
3021 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]);
3023 memset(types,0,sizeof(types));
3024 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3025 for (i = 0; i < 3; i++)
3026 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]));
3027 memset(types,0,sizeof(types));
3028 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3029 for (i = 0; i < 5; i++)
3030 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3032 memset(types,0,sizeof(types));
3033 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3034 for (i = 0; i < 8; i++)
3035 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);
3037 memset(types,0,sizeof(types));
3038 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3039 for (i = 0; i < 7; i++)
3040 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]);
3042 memset(types,0,sizeof(types));
3043 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3044 for (i = 0; i < 7; i++)
3045 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));
3048 memset(types,0,sizeof(types));
3049 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3050 for (i = 0; i < 12; i++)
3051 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);
3053 memset(types,0,sizeof(types));
3054 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3055 for (i = 0; i < 3; i++)
3056 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);
3058 memset(types,0,sizeof(types));
3059 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3060 for (i = 0; i < 2; i++)
3061 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);
3063 memset(types,0,sizeof(types));
3064 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3065 for (i = 0; i < 20; i++)
3066 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);
3068 memset(types,0,sizeof(types));
3069 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3070 for (i = 0; i < 3; i++)
3071 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 );
3074 static void test_IdnToNameprepUnicode(void)
3080 const WCHAR out[64];
3086 5, {'t','e','s','t',0},
3087 5, {'t','e','s','t',0},
3091 3, {'a',0xe111,'b'},
3093 0, ERROR_INVALID_NAME
3098 0, ERROR_INVALID_NAME
3108 0, ERROR_INVALID_NAME
3111 6, {' ','-','/','[',']',0},
3112 6, {' ','-','/','[',']',0},
3118 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3123 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3125 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3126 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3127 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3131 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3135 { /* Another example of incorrectly working FoldString (composition) */
3143 0, ERROR_NO_UNICODE_TRANSLATION
3148 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3151 5, {'a','.','.','a',0},
3153 0, ERROR_INVALID_NAME
3165 if (!pIdnToNameprepUnicode)
3167 win_skip("IdnToNameprepUnicode is not available\n");
3171 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3172 test_data[0].in_len, NULL, 0);
3173 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3175 SetLastError(0xdeadbeef);
3176 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3177 test_data[1].in_len, NULL, 0);
3178 err = GetLastError();
3179 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3180 ok(err == test_data[1].err, "err = %d\n", err);
3182 SetLastError(0xdeadbeef);
3183 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3184 buf, sizeof(buf)/sizeof(WCHAR));
3185 err = GetLastError();
3186 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3187 ok(err == 0xdeadbeef, "err = %d\n", err);
3189 SetLastError(0xdeadbeef);
3190 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3191 buf, sizeof(buf)/sizeof(WCHAR));
3192 err = GetLastError();
3193 ok(ret == 0, "ret = %d\n", ret);
3194 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3196 SetLastError(0xdeadbeef);
3197 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3198 buf, sizeof(buf)/sizeof(WCHAR));
3199 err = GetLastError();
3200 ok(ret == 0, "ret = %d\n", ret);
3201 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3203 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3204 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3205 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3207 SetLastError(0xdeadbeef);
3208 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3209 err = GetLastError();
3210 ok(ret == 0, "ret = %d\n", ret);
3211 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3213 SetLastError(0xdeadbeef);
3214 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3215 err = GetLastError();
3216 ok(ret == 0, "ret = %d\n", ret);
3217 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3219 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3221 SetLastError(0xdeadbeef);
3222 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3223 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3224 err = GetLastError();
3225 if(!test_data[i].todo) {
3226 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3227 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3228 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3229 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3231 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3232 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3237 static void test_IdnToAscii(void)
3243 const WCHAR out[64];
3248 5, {'T','e','s','t',0},
3249 5, {'T','e','s','t',0},
3253 5, {'T','e',0x017c,'s','t',0},
3254 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3258 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3259 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3264 9, {'x','n','-','-','2','d','a','.',0},
3268 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3269 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3273 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3274 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3275 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3280 8, {'x','n','-','-','6','l','a',0},
3281 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3290 win_skip("IdnToAscii is not available\n");
3294 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3296 SetLastError(0xdeadbeef);
3297 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3298 test_data[i].in_len, buf, sizeof(buf));
3299 err = GetLastError();
3300 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3301 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3302 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3303 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3307 static void test_IdnToUnicode(void)
3313 const WCHAR out[64];
3318 5, {'T','e','s','.',0},
3319 5, {'T','e','s','.',0},
3325 0, ERROR_INVALID_NAME
3328 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3329 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3330 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3331 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3332 0x05d1,0x05e8,0x05d9,0x05ea,0},
3336 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3337 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3338 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3339 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3343 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3344 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3345 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3346 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3348 0, ERROR_INVALID_NAME
3351 8, {'x','n','-','-','6','l','a',0},
3353 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3362 win_skip("IdnToUnicode is not available\n");
3366 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3368 SetLastError(0xdeadbeef);
3369 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3370 test_data[i].in_len, buf, sizeof(buf));
3371 err = GetLastError();
3372 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3373 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3374 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3375 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3379 static void test_GetLocaleInfoEx(void)
3381 static const WCHAR enW[] = {'e','n',0};
3385 if (!pGetLocaleInfoEx)
3387 win_skip("GetLocaleInfoEx not supported\n");
3391 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3392 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3395 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3396 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3397 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3398 static const WCHAR usaW[] = {'U','S','A',0};
3399 static const WCHAR enuW[] = {'E','N','U',0};
3400 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3404 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3406 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3407 ok(ret, "got %d\n", ret);
3408 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3410 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3411 ok(ret, "got %d\n", ret);
3412 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3414 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3415 ok(ret, "got %d\n", ret);
3416 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3418 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3419 ok(ret, "got %d\n", ret);
3420 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3423 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3425 ok(!ret, "got %d\n", ret);
3430 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3433 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3435 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3437 pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3439 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3445 static void test_IsValidLocaleName(void)
3447 static const WCHAR enW[] = {'e','n',0};
3448 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3449 static const WCHAR zzW[] = {'z','z',0};
3450 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3453 if (!pIsValidLocaleName)
3455 win_skip("IsValidLocaleName not supported\n");
3459 ret = pIsValidLocaleName(enW);
3460 ok(ret, "IsValidLocaleName failed\n");
3461 ret = pIsValidLocaleName(enusW);
3462 ok(ret, "IsValidLocaleName failed\n");
3463 ret = pIsValidLocaleName(zzW);
3464 ok(!ret, "IsValidLocaleName should have failed\n");
3465 ret = pIsValidLocaleName(zzzzW);
3466 ok(!ret, "IsValidLocaleName should have failed\n");
3471 InitFunctionPointers();
3474 test_EnumTimeFormatsA();
3475 test_EnumDateFormatsA();
3476 test_GetLocaleInfoA();
3477 test_GetLocaleInfoW();
3478 test_GetLocaleInfoEx();
3479 test_GetTimeFormatA();
3480 test_GetDateFormatA();
3481 test_GetDateFormatW();
3482 test_GetCurrencyFormatA(); /* Also tests the W version */
3483 test_GetNumberFormatA(); /* Also tests the W version */
3484 test_CompareStringA();
3485 test_LCMapStringA();
3486 test_LCMapStringW();
3487 test_LCMapStringEx();
3488 test_LocaleNameToLCID();
3491 test_ConvertDefaultLocale();
3492 test_EnumSystemLanguageGroupsA();
3493 test_EnumSystemLocalesEx();
3494 test_EnumLanguageGroupLocalesA();
3495 test_SetLocaleInfoA();
3496 test_EnumUILanguageA();
3498 test_GetStringTypeW();
3499 test_IdnToNameprepUnicode();
3501 test_IdnToUnicode();
3502 test_IsValidLocaleName();
3503 /* this requires collation table patch to make it MS compatible */
3504 if (0) test_sorting();