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);
90 static void InitFunctionPointers(void)
92 hKernel32 = GetModuleHandleA("kernel32");
93 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
94 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
95 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
96 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
97 pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
98 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
99 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
100 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
101 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
102 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
103 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
104 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
105 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
106 pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
109 #define eq(received, expected, label, type) \
110 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
111 (label), (received), (expected))
113 #define BUFFER_SIZE 128
114 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
116 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
117 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
118 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
119 "Expected '%s', got '%s'\n", Expected, buffer)
121 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
122 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
123 SetLastError(0xdeadbeef); buffer[0] = '\0'
124 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
125 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
127 #define NUO LOCALE_NOUSEROVERRIDE
129 static void test_GetLocaleInfoA(void)
133 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
134 char buffer[BUFFER_SIZE];
135 char expected[BUFFER_SIZE];
138 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
140 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
141 ok(ret, "got %d\n", ret);
142 ok(val == lcid, "got 0x%08x\n", val);
144 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
145 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
146 assumes SUBLANG_NEUTRAL for zh */
147 memset(expected, 0, COUNTOF(expected));
148 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
149 SetLastError(0xdeadbeef);
150 memset(buffer, 0, COUNTOF(buffer));
151 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
152 ok((ret == len) && !lstrcmpA(buffer, expected),
153 "got %d with '%s' (expected %d with '%s')\n",
154 ret, buffer, len, expected);
156 memset(expected, 0, COUNTOF(expected));
157 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
159 SetLastError(0xdeadbeef);
160 memset(buffer, 0, COUNTOF(buffer));
161 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
162 ok((ret == len) && !lstrcmpA(buffer, expected),
163 "got %d with '%s' (expected %d with '%s')\n",
164 ret, buffer, len, expected);
167 win_skip("LANG_ARABIC not installed\n");
169 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
170 memset(expected, 0, COUNTOF(expected));
171 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
172 SetLastError(0xdeadbeef);
173 memset(buffer, 0, COUNTOF(buffer));
174 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
175 ok((ret == len) && !lstrcmpA(buffer, expected),
176 "got %d with '%s' (expected %d with '%s')\n",
177 ret, buffer, len, expected);
180 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
181 * partially fill the buffer even if it is too short. See bug 637.
183 SetLastError(0xdeadbeef);
184 memset(buffer, 0, COUNTOF(buffer));
185 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
186 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
188 SetLastError(0xdeadbeef);
189 memset(buffer, 0, COUNTOF(buffer));
190 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
191 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
192 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
193 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
195 SetLastError(0xdeadbeef);
196 memset(buffer, 0, COUNTOF(buffer));
197 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
198 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
199 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
202 struct neutralsublang_name2_t {
207 WCHAR sname_broken[15];
211 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
212 { {'a','r',0}, {'a','r','-','S','A',0},
213 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
214 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
215 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
216 { {'d','e',0}, {'d','e','-','D','E',0},
217 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
218 { {'e','n',0}, {'e','n','-','U','S',0},
219 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
220 { {'e','s',0}, {'e','s','-','E','S',0},
221 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
222 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
223 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
224 { {'g','a',0}, {'g','a','-','I','E',0},
225 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
226 { {'i','t',0}, {'i','t','-','I','T',0},
227 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
228 { {'m','s',0}, {'m','s','-','M','Y',0},
229 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
230 { {'n','l',0}, {'n','l','-','N','L',0},
231 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
232 { {'p','t',0}, {'p','t','-','B','R',0},
233 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
234 { {'s','r',0}, {'h','r','-','H','R',0},
235 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
236 { {'s','v',0}, {'s','v','-','S','E',0},
237 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
238 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
239 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
240 { {'z','h',0}, {'z','h','-','C','N',0},
241 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
245 static void test_GetLocaleInfoW(void)
247 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
248 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
249 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
250 WCHAR bufferW[80], buffer2W[80];
256 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
258 win_skip("GetLocaleInfoW() isn't implemented\n");
262 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
263 ok(ret, "got %d\n", ret);
264 ok(val == lcid_en, "got 0x%08x\n", val);
266 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
269 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
270 'S','t','a','t','e','s',')',0};
271 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
272 static const WCHAR enW[] = {'e','n','-','U','S',0};
273 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
275 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
277 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
278 ok(ret, "got %d\n", ret);
279 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
281 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
282 ok(ret, "got %d\n", ret);
283 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
290 /* make neutral lcid */
291 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
292 lcid = MAKELCID(langid, SORT_DEFAULT);
295 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
299 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
300 wine_dbgstr_w(ptr->name), val, ptr->lcid);
303 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
304 wine_dbgstr_w(ptr->name), val, ptr->lcid);
306 /* now check LOCALE_SNAME */
307 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
310 ok(!lstrcmpW(bufferW, ptr->sname) ||
311 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
312 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
314 ok(!lstrcmpW(bufferW, ptr->sname) ||
315 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
316 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
321 win_skip("English neutral locale not supported\n");
323 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
325 win_skip("LANG_RUSSIAN locale data unavailable\n");
328 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
329 bufferW, COUNTOF(bufferW));
331 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
335 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
337 SetLastError(0xdeadbeef);
338 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
339 bufferA, COUNTOF(bufferA));
340 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
341 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
342 ok(GetLastError() == ERROR_INVALID_FLAGS,
343 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
346 SetLastError(0xdeadbeef);
347 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
348 bufferW, COUNTOF(bufferW));
350 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
351 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
352 ok(GetLastError() == ERROR_INVALID_FLAGS,
353 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
355 /* yes, test empty 13 month entry too */
356 for (i = 0; i < 12; i++) {
358 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
359 bufferW, COUNTOF(bufferW));
360 ok(ret, "Expected non zero result\n");
361 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
362 ret, lstrlenW(bufferW));
364 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
365 buffer2W, COUNTOF(buffer2W));
366 ok(ret, "Expected non zero result\n");
367 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
368 ret, lstrlenW(buffer2W));
370 ok(lstrcmpW(bufferW, buffer2W) != 0,
371 "Expected genitive name to differ, got the same for month %d\n", i+1);
373 /* for locale without genitive names nominative returned in both cases */
375 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
376 bufferW, COUNTOF(bufferW));
377 ok(ret, "Expected non zero result\n");
378 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
379 ret, lstrlenW(bufferW));
381 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
382 buffer2W, COUNTOF(buffer2W));
383 ok(ret, "Expected non zero result\n");
384 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
385 ret, lstrlenW(buffer2W));
387 ok(lstrcmpW(bufferW, buffer2W) == 0,
388 "Expected same names, got different for month %d\n", i+1);
392 static void test_GetTimeFormatA(void)
396 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
397 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
399 memset(&curtime, 2, sizeof(SYSTEMTIME));
400 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
401 SetLastError(0xdeadbeef);
402 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
403 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
404 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
407 curtime.wMinute = 56;
408 curtime.wSecond = 13;
409 curtime.wMilliseconds = 22;
410 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
411 SetLastError(0xdeadbeef);
412 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
413 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
414 EXPECT_LENA; EXPECT_EQA;
416 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
417 SetLastError(0xdeadbeef);
418 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
419 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
420 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
422 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
423 SetLastError(0xdeadbeef);
424 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
425 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
426 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
428 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
429 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
430 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
433 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
434 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
435 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
436 EXPECT_LENA; EXPECT_EQA;
438 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
439 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
440 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
441 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
442 "Expected '', got '%s'\n", buffer );
444 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
445 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
446 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
447 EXPECT_LENA; EXPECT_EQA;
449 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
450 strcpy(Expected, "8:56 AM");
451 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
452 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
453 EXPECT_LENA; EXPECT_EQA;
455 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
456 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
457 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
458 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
459 "Expected '8.@:56AM', got '%s'\n", buffer );
461 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
462 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
463 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
464 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
465 "Expected '', got '%s'\n", buffer );
467 STRINGSA("t/tt", "A/AM"); /* AM time marker */
468 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
469 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
470 EXPECT_LENA; EXPECT_EQA;
473 STRINGSA("t/tt", "P/PM"); /* PM time marker */
474 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
475 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
476 EXPECT_LENA; EXPECT_EQA;
478 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
479 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
480 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
481 EXPECT_LENA; EXPECT_EQA;
483 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
484 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
485 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
486 EXPECT_LENA; EXPECT_EQA;
488 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
489 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
490 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
491 EXPECT_LENA; EXPECT_EQA;
493 curtime.wHour = 14; /* change this to 14 or 2pm */
496 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 */
497 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
498 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
499 EXPECT_LENA; EXPECT_EQA;
502 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
503 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
504 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
505 EXPECT_LENA; EXPECT_EQA;
507 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
508 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
509 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
510 EXPECT_LENA; EXPECT_EQA;
512 /* try to convert formatting strings with more than two letters
513 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
514 * NOTE: We expect any letter for which there is an upper case value
515 * we should see a replacement. For letters that DO NOT have
516 * upper case values we should see NO REPLACEMENT.
519 curtime.wMinute = 56;
520 curtime.wSecond = 13;
521 curtime.wMilliseconds = 22;
522 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
523 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
524 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
526 EXPECT_LENA; EXPECT_EQA;
528 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
529 strcpy(buffer, "text");
530 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
531 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
534 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
535 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
536 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
537 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
538 EXPECT_LENA; EXPECT_EQA;
540 STRINGSA("'''", "'"); /* invalid quoted string */
541 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
543 EXPECT_LENA; EXPECT_EQA;
545 /* test that msdn suggested single quotation usage works as expected */
546 STRINGSA("''''", "'"); /* single quote mark */
547 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
548 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
549 EXPECT_LENA; EXPECT_EQA;
551 STRINGSA("''HHHHHH", "08"); /* Normal use */
552 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
553 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
554 EXPECT_LENA; EXPECT_EQA;
556 /* and test for normal use of the single quotation mark */
557 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
558 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
559 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
560 EXPECT_LENA; EXPECT_EQA;
562 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
563 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
564 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
565 EXPECT_LENA; EXPECT_EQA;
567 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
568 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
569 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
570 EXPECT_LENA; EXPECT_EQA;
573 STRINGSA("'123'tt", ""); /* Invalid time */
574 SetLastError(0xdeadbeef);
575 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
576 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
577 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
580 curtime.wMonth = 60; /* Invalid */
581 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
582 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
583 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
584 EXPECT_LENA; EXPECT_EQA;
587 static void test_GetDateFormatA(void)
591 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
592 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
593 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
594 char Broken[BUFFER_SIZE];
595 char short_day[10], month[10], genitive_month[10];
597 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
598 STRINGSA("ddd',' MMM dd yy","");
599 SetLastError(0xdeadbeef);
600 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
601 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
602 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
604 curtime.wYear = 2002;
607 curtime.wDayOfWeek = 3;
608 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
609 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
610 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
611 EXPECT_LENA; EXPECT_EQA;
613 /* Same as above but with LOCALE_NOUSEROVERRIDE */
614 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
615 SetLastError(0xdeadbeef);
616 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
617 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
618 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
621 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
622 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
623 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
624 EXPECT_LENA; EXPECT_EQA;
626 curtime.wHour = 36; /* Invalid */
627 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
628 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
629 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
630 EXPECT_LENA; EXPECT_EQA;
632 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
633 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
634 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
637 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
638 SetLastError(0xdeadbeef);
639 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
640 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
641 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
643 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
644 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
645 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
646 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
647 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
649 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
650 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
651 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
652 EXPECT_LENA; EXPECT_EQA;
654 /* test for expected DATE_YEARMONTH behavior with null format */
655 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
656 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
657 SetLastError(0xdeadbeef);
658 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
659 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
660 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
663 /* Test that using invalid DATE_* flags results in the correct error */
664 /* and return values */
665 STRINGSA("m/d/y", ""); /* Invalid flags */
666 SetLastError(0xdeadbeef);
667 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
668 &curtime, input, buffer, COUNTOF(buffer));
669 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
670 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
672 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
675 win_skip("LANG_RUSSIAN locale data unavailable\n");
679 /* month part should be in genitive form */
680 strcpy(genitive_month, buffer + 2);
681 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
682 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
683 strcpy(month, buffer);
684 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
686 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
687 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
688 strcpy(short_day, buffer);
690 STRINGSA("dd MMMMddd dd", "");
691 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
692 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
693 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
696 STRINGSA("MMMMddd dd", "");
697 sprintf(Expected, "%s%s 04", month, short_day);
698 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
699 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 STRINGSA("MMMMddd", "");
703 sprintf(Expected, "%s%s", month, short_day);
704 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
705 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 STRINGSA("MMMMdd", "");
709 sprintf(Expected, "%s04", genitive_month);
710 sprintf(Broken, "%s04", month);
711 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
714 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
715 "Expected '%s', got '%s'\n", Expected, buffer);
717 STRINGSA("MMMMdd ddd", "");
718 sprintf(Expected, "%s04 %s", genitive_month, short_day);
719 sprintf(Broken, "%s04 %s", month, short_day);
720 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
721 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
722 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
723 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
724 "Expected '%s', got '%s'\n", Expected, buffer);
726 STRINGSA("dd dddMMMM", "");
727 sprintf(Expected, "04 %s%s", short_day, month);
728 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
729 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
732 STRINGSA("dd dddMMMM ddd MMMMdd", "");
733 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
734 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
735 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
736 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
737 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
738 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
739 "Expected '%s', got '%s'\n", Expected, buffer);
741 /* with literal part */
742 STRINGSA("ddd',' MMMM dd", "");
743 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
744 sprintf(Broken, "%s, %s 04", short_day, month);
745 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
746 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
747 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
748 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
749 "Expected '%s', got '%s'\n", Expected, buffer);
752 static void test_GetDateFormatW(void)
756 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
757 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
759 STRINGSW("",""); /* If flags is not zero then format must be NULL */
760 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
761 input, buffer, COUNTOF(buffer));
762 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
764 win_skip("GetDateFormatW is not implemented\n");
767 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
768 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
771 STRINGSW("",""); /* NULL buffer, len > 0 */
772 SetLastError(0xdeadbeef);
773 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
774 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
775 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
777 STRINGSW("",""); /* NULL buffer, len == 0 */
778 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
779 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
780 EXPECT_LENW; EXPECT_EQW;
782 curtime.wYear = 2002;
785 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
786 curtime.wHour = 65432; /* Invalid */
787 curtime.wMinute = 34512; /* Invalid */
788 curtime.wSecond = 65535; /* Invalid */
789 curtime.wMilliseconds = 12345;
790 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
791 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
792 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
793 EXPECT_LENW; EXPECT_EQW;
797 curtime.wYear = 1601;
800 curtime.wDayOfWeek = 0; /* Irrelevant */
804 curtime.wMilliseconds = 0;
805 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
806 SetLastError(0xdeadbeef);
807 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
808 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
809 EXPECT_LENW; EXPECT_EQW;
811 curtime.wYear = 1600;
814 curtime.wDayOfWeek = 0; /* Irrelevant */
816 curtime.wMinute = 59;
817 curtime.wSecond = 59;
818 curtime.wMilliseconds = 999;
819 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
820 SetLastError(0xdeadbeef);
821 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
822 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
823 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
827 #define CY_POS_LEFT 0
828 #define CY_POS_RIGHT 1
829 #define CY_POS_LEFT_SPACE 2
830 #define CY_POS_RIGHT_SPACE 3
832 static void test_GetCurrencyFormatA(void)
834 static char szDot[] = { '.', '\0' };
835 static char szComma[] = { ',', '\0' };
836 static char szDollar[] = { '$', '\0' };
838 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
839 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
842 memset(&format, 0, sizeof(format));
844 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
845 SetLastError(0xdeadbeef);
846 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
847 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
848 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
850 STRINGSA("23,53",""); /* Invalid character --> Error */
851 SetLastError(0xdeadbeef);
852 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
853 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
854 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
856 STRINGSA("--",""); /* Double '-' --> Error */
857 SetLastError(0xdeadbeef);
858 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
859 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
860 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
862 STRINGSA("0-",""); /* Trailing '-' --> Error */
863 SetLastError(0xdeadbeef);
864 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
865 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
866 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
868 STRINGSA("0..",""); /* Double '.' --> Error */
869 SetLastError(0xdeadbeef);
870 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
871 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
872 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
874 STRINGSA(" 0.1",""); /* Leading space --> Error */
875 SetLastError(0xdeadbeef);
876 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
877 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
878 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
880 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
881 SetLastError(0xdeadbeef);
882 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
883 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
884 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
886 STRINGSA("2353",""); /* Format and flags given --> Error */
887 SetLastError(0xdeadbeef);
888 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
889 ok( !ret, "Expected ret == 0, got %d\n", ret);
890 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
891 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
893 STRINGSA("2353",""); /* Invalid format --> Error */
894 SetLastError(0xdeadbeef);
895 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
896 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
897 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
899 STRINGSA("2353","$2,353.00"); /* Valid number */
900 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
901 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
902 EXPECT_LENA; EXPECT_EQA;
904 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
905 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
906 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
907 EXPECT_LENA; EXPECT_EQA;
909 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
910 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
911 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
912 EXPECT_LENA; EXPECT_EQA;
914 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
915 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 EXPECT_LENA; EXPECT_EQA;
919 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
920 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
921 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
922 EXPECT_LENA; EXPECT_EQA;
924 format.NumDigits = 0; /* No decimal separator */
925 format.LeadingZero = 0;
926 format.Grouping = 0; /* No grouping char */
927 format.NegativeOrder = 0;
928 format.PositiveOrder = CY_POS_LEFT;
929 format.lpDecimalSep = szDot;
930 format.lpThousandSep = szComma;
931 format.lpCurrencySymbol = szDollar;
933 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
934 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
935 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
936 EXPECT_LENA; EXPECT_EQA;
938 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
939 STRINGSA("2353","$2353.0");
940 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
941 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942 EXPECT_LENA; EXPECT_EQA;
944 format.Grouping = 2; /* Group by 100's */
945 STRINGSA("2353","$23,53.0");
946 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
947 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
948 EXPECT_LENA; EXPECT_EQA;
950 STRINGSA("235","$235.0"); /* Grouping of a positive number */
952 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
953 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
954 EXPECT_LENA; EXPECT_EQA;
956 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
957 format.NegativeOrder = 2;
958 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
959 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
960 EXPECT_LENA; EXPECT_EQA;
962 format.LeadingZero = 1; /* Always provide leading zero */
963 STRINGSA(".5","$0.5");
964 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
965 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
966 EXPECT_LENA; EXPECT_EQA;
968 format.PositiveOrder = CY_POS_RIGHT;
969 STRINGSA("1","1.0$");
970 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
971 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
972 EXPECT_LENA; EXPECT_EQA;
974 format.PositiveOrder = CY_POS_LEFT_SPACE;
975 STRINGSA("1","$ 1.0");
976 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
977 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
978 EXPECT_LENA; EXPECT_EQA;
980 format.PositiveOrder = CY_POS_RIGHT_SPACE;
981 STRINGSA("1","1.0 $");
982 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
983 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
984 EXPECT_LENA; EXPECT_EQA;
986 format.NegativeOrder = 0;
987 STRINGSA("-1","($1.0)");
988 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
989 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
990 EXPECT_LENA; EXPECT_EQA;
992 format.NegativeOrder = 1;
993 STRINGSA("-1","-$1.0");
994 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
995 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
996 EXPECT_LENA; EXPECT_EQA;
998 format.NegativeOrder = 2;
999 STRINGSA("-1","$-1.0");
1000 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1001 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1002 EXPECT_LENA; EXPECT_EQA;
1004 format.NegativeOrder = 3;
1005 STRINGSA("-1","$1.0-");
1006 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1007 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1008 EXPECT_LENA; EXPECT_EQA;
1010 format.NegativeOrder = 4;
1011 STRINGSA("-1","(1.0$)");
1012 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1013 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1014 EXPECT_LENA; EXPECT_EQA;
1016 format.NegativeOrder = 5;
1017 STRINGSA("-1","-1.0$");
1018 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1019 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1020 EXPECT_LENA; EXPECT_EQA;
1022 format.NegativeOrder = 6;
1023 STRINGSA("-1","1.0-$");
1024 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1025 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1026 EXPECT_LENA; EXPECT_EQA;
1028 format.NegativeOrder = 7;
1029 STRINGSA("-1","1.0$-");
1030 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1031 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1032 EXPECT_LENA; EXPECT_EQA;
1034 format.NegativeOrder = 8;
1035 STRINGSA("-1","-1.0 $");
1036 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1037 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1038 EXPECT_LENA; EXPECT_EQA;
1040 format.NegativeOrder = 9;
1041 STRINGSA("-1","-$ 1.0");
1042 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1043 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1044 EXPECT_LENA; EXPECT_EQA;
1046 format.NegativeOrder = 10;
1047 STRINGSA("-1","1.0 $-");
1048 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1049 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1050 EXPECT_LENA; EXPECT_EQA;
1052 format.NegativeOrder = 11;
1053 STRINGSA("-1","$ 1.0-");
1054 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1055 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1056 EXPECT_LENA; EXPECT_EQA;
1058 format.NegativeOrder = 12;
1059 STRINGSA("-1","$ -1.0");
1060 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1061 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1062 EXPECT_LENA; EXPECT_EQA;
1064 format.NegativeOrder = 13;
1065 STRINGSA("-1","1.0- $");
1066 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1067 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1068 EXPECT_LENA; EXPECT_EQA;
1070 format.NegativeOrder = 14;
1071 STRINGSA("-1","($ 1.0)");
1072 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1073 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1074 EXPECT_LENA; EXPECT_EQA;
1076 format.NegativeOrder = 15;
1077 STRINGSA("-1","(1.0 $)");
1078 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1079 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1080 EXPECT_LENA; EXPECT_EQA;
1083 #define NEG_PARENS 0 /* "(1.1)" */
1084 #define NEG_LEFT 1 /* "-1.1" */
1085 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1086 #define NEG_RIGHT 3 /* "1.1-" */
1087 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1089 static void test_GetNumberFormatA(void)
1091 static char szDot[] = { '.', '\0' };
1092 static char szComma[] = { ',', '\0' };
1094 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1095 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1098 memset(&format, 0, sizeof(format));
1100 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1101 SetLastError(0xdeadbeef);
1102 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1103 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1104 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1106 STRINGSA("23,53",""); /* Invalid character --> Error */
1107 SetLastError(0xdeadbeef);
1108 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1109 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1110 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1112 STRINGSA("--",""); /* Double '-' --> Error */
1113 SetLastError(0xdeadbeef);
1114 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1115 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1116 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1118 STRINGSA("0-",""); /* Trailing '-' --> Error */
1119 SetLastError(0xdeadbeef);
1120 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1121 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1122 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1124 STRINGSA("0..",""); /* Double '.' --> Error */
1125 SetLastError(0xdeadbeef);
1126 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1127 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1128 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1130 STRINGSA(" 0.1",""); /* Leading space --> Error */
1131 SetLastError(0xdeadbeef);
1132 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1133 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1134 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1136 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1137 SetLastError(0xdeadbeef);
1138 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1139 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1140 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1142 STRINGSA("2353",""); /* Format and flags given --> Error */
1143 SetLastError(0xdeadbeef);
1144 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1145 ok( !ret, "Expected ret == 0, got %d\n", ret);
1146 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1147 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1149 STRINGSA("2353",""); /* Invalid format --> Error */
1150 SetLastError(0xdeadbeef);
1151 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1152 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1153 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1155 STRINGSA("2353","2,353.00"); /* Valid number */
1156 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1157 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1158 EXPECT_LENA; EXPECT_EQA;
1160 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1161 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1162 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1163 EXPECT_LENA; EXPECT_EQA;
1165 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1166 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1167 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1168 EXPECT_LENA; EXPECT_EQA;
1170 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1171 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1172 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1173 EXPECT_LENA; EXPECT_EQA;
1175 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1176 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1177 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1178 EXPECT_LENA; EXPECT_EQA;
1180 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1181 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1182 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1183 EXPECT_LENA; EXPECT_EQA;
1185 format.NumDigits = 0; /* No decimal separator */
1186 format.LeadingZero = 0;
1187 format.Grouping = 0; /* No grouping char */
1188 format.NegativeOrder = 0;
1189 format.lpDecimalSep = szDot;
1190 format.lpThousandSep = szComma;
1192 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1193 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1194 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1195 EXPECT_LENA; EXPECT_EQA;
1197 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1198 STRINGSA("2353","2353.0");
1199 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1200 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1201 EXPECT_LENA; EXPECT_EQA;
1203 format.Grouping = 2; /* Group by 100's */
1204 STRINGSA("2353","23,53.0");
1205 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1206 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1207 EXPECT_LENA; EXPECT_EQA;
1209 STRINGSA("235","235.0"); /* Grouping of a positive number */
1210 format.Grouping = 3;
1211 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1212 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1213 EXPECT_LENA; EXPECT_EQA;
1215 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1216 format.NegativeOrder = NEG_LEFT;
1217 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1218 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1219 EXPECT_LENA; EXPECT_EQA;
1221 format.LeadingZero = 1; /* Always provide leading zero */
1222 STRINGSA(".5","0.5");
1223 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1224 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1225 EXPECT_LENA; EXPECT_EQA;
1227 format.NegativeOrder = NEG_PARENS;
1228 STRINGSA("-1","(1.0)");
1229 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1230 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1231 EXPECT_LENA; EXPECT_EQA;
1233 format.NegativeOrder = NEG_LEFT;
1234 STRINGSA("-1","-1.0");
1235 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1237 EXPECT_LENA; EXPECT_EQA;
1239 format.NegativeOrder = NEG_LEFT_SPACE;
1240 STRINGSA("-1","- 1.0");
1241 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1242 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1243 EXPECT_LENA; EXPECT_EQA;
1245 format.NegativeOrder = NEG_RIGHT;
1246 STRINGSA("-1","1.0-");
1247 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1248 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1249 EXPECT_LENA; EXPECT_EQA;
1251 format.NegativeOrder = NEG_RIGHT_SPACE;
1252 STRINGSA("-1","1.0 -");
1253 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1254 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1255 EXPECT_LENA; EXPECT_EQA;
1257 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1259 if (IsValidLocale(lcid, 0))
1261 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1262 Expected[3] = 160; /* Non breaking space */
1263 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1264 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1265 EXPECT_LENA; EXPECT_EQA;
1269 struct comparestringa_entry {
1279 static const struct comparestringa_entry comparestringa_data[] = {
1280 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1281 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1282 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1283 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1284 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1285 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1286 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1287 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1288 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1289 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1290 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1291 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1292 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1293 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1294 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1295 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1296 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1297 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1298 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1299 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1300 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1301 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1302 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1303 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1304 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1305 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1306 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1307 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1308 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1309 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1312 static void test_CompareStringA(void)
1315 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1317 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1319 const struct comparestringa_entry *entry = &comparestringa_data[i];
1321 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1322 entry->second, entry->second_len);
1323 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1326 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1327 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1329 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1330 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1332 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1333 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1335 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1336 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1338 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1340 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1341 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1343 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1344 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1346 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1347 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1349 /* test for CompareStringA flags */
1350 SetLastError(0xdeadbeef);
1351 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1352 ok(GetLastError() == ERROR_INVALID_FLAGS,
1353 "unexpected error code %d\n", GetLastError());
1354 ok(!ret, "CompareStringA must fail with invalid flag\n");
1356 SetLastError(0xdeadbeef);
1357 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1358 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1359 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1360 /* end of test for CompareStringA flags */
1362 ret = lstrcmpA("", "");
1363 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1365 ret = lstrcmpA(NULL, NULL);
1366 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1368 ret = lstrcmpA("", NULL);
1369 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1371 ret = lstrcmpA(NULL, "");
1372 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1375 if (0) { /* this requires collation table patch to make it MS compatible */
1376 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1377 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1379 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1380 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1382 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1383 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1385 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1386 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1388 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1389 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1391 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1392 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1394 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1395 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1397 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1398 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1400 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1401 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1403 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1404 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1406 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1407 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1409 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1410 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1414 /* WinXP handles embedded NULLs differently than earlier versions */
1415 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1416 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1418 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1419 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);
1421 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1422 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1424 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1425 ok(ret == CSTR_EQUAL || /* win2k */
1426 ret == CSTR_GREATER_THAN,
1427 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1429 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1430 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1432 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1433 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1435 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1436 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1438 ret = lstrcmpi("#", ".");
1439 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1441 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1443 /* \xB9 character lies between a and b */
1444 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1445 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1446 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1447 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1450 static void test_LCMapStringA(void)
1453 char buf[256], buf2[256];
1454 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1455 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1456 static const char symbols_stripped[] = "justateststring1";
1458 SetLastError(0xdeadbeef);
1459 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1460 lower_case, -1, buf, sizeof(buf));
1461 ok(ret == lstrlenA(lower_case) + 1,
1462 "ret %d, error %d, expected value %d\n",
1463 ret, GetLastError(), lstrlenA(lower_case) + 1);
1464 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1466 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1467 upper_case, -1, buf, sizeof(buf));
1468 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1469 ok(GetLastError() == ERROR_INVALID_FLAGS,
1470 "unexpected error code %d\n", GetLastError());
1472 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1473 upper_case, -1, buf, sizeof(buf));
1474 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1475 ok(GetLastError() == ERROR_INVALID_FLAGS,
1476 "unexpected error code %d\n", GetLastError());
1478 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1479 upper_case, -1, buf, sizeof(buf));
1480 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1481 ok(GetLastError() == ERROR_INVALID_FLAGS,
1482 "unexpected error code %d\n", GetLastError());
1484 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1485 upper_case, -1, buf, sizeof(buf));
1486 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1487 ok(GetLastError() == ERROR_INVALID_FLAGS,
1488 "unexpected error code %d\n", GetLastError());
1490 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1491 SetLastError(0xdeadbeef);
1492 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1493 upper_case, -1, buf, sizeof(buf));
1494 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1495 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1497 /* test LCMAP_LOWERCASE */
1498 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1499 upper_case, -1, buf, sizeof(buf));
1500 ok(ret == lstrlenA(upper_case) + 1,
1501 "ret %d, error %d, expected value %d\n",
1502 ret, GetLastError(), lstrlenA(upper_case) + 1);
1503 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1505 /* test LCMAP_UPPERCASE */
1506 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1507 lower_case, -1, buf, sizeof(buf));
1508 ok(ret == lstrlenA(lower_case) + 1,
1509 "ret %d, error %d, expected value %d\n",
1510 ret, GetLastError(), lstrlenA(lower_case) + 1);
1511 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1513 /* test buffer overflow */
1514 SetLastError(0xdeadbeef);
1515 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1516 lower_case, -1, buf, 4);
1517 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1518 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1520 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1521 lstrcpyA(buf, lower_case);
1522 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1523 buf, -1, buf, sizeof(buf));
1524 if (!ret) /* Win9x */
1525 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1528 ok(ret == lstrlenA(lower_case) + 1,
1529 "ret %d, error %d, expected value %d\n",
1530 ret, GetLastError(), lstrlenA(lower_case) + 1);
1531 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1533 lstrcpyA(buf, upper_case);
1534 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1535 buf, -1, buf, sizeof(buf));
1536 if (!ret) /* Win9x */
1537 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1540 ok(ret == lstrlenA(upper_case) + 1,
1541 "ret %d, error %d, expected value %d\n",
1542 ret, GetLastError(), lstrlenA(lower_case) + 1);
1543 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1546 /* otherwise src == dst should fail */
1547 SetLastError(0xdeadbeef);
1548 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1549 buf, 10, buf, sizeof(buf));
1550 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1551 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1552 "unexpected error code %d\n", GetLastError());
1553 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1555 /* test whether '\0' is always appended */
1556 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1557 upper_case, -1, buf, sizeof(buf));
1558 ok(ret, "LCMapStringA must succeed\n");
1559 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1560 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1561 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1562 ok(ret2, "LCMapStringA must succeed\n");
1563 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1564 ok(ret == ret2, "lengths of sort keys must be equal\n");
1565 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1567 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1568 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1569 upper_case, -1, buf, sizeof(buf));
1570 ok(ret, "LCMapStringA must succeed\n");
1571 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1572 lower_case, -1, buf2, sizeof(buf2));
1573 ok(ret2, "LCMapStringA must succeed\n");
1574 ok(ret == ret2, "lengths of sort keys must be equal\n");
1575 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1577 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1578 results from plain LCMAP_SORTKEY on Vista */
1580 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1581 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1582 lower_case, -1, buf, sizeof(buf));
1583 ok(ret, "LCMapStringA must succeed\n");
1584 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1585 symbols_stripped, -1, buf2, sizeof(buf2));
1586 ok(ret2, "LCMapStringA must succeed\n");
1587 ok(ret == ret2, "lengths of sort keys must be equal\n");
1588 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1590 /* test NORM_IGNORENONSPACE */
1591 lstrcpyA(buf, "foo");
1592 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1593 lower_case, -1, buf, sizeof(buf));
1594 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1595 lstrlenA(lower_case) + 1, ret);
1596 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1598 /* test NORM_IGNORESYMBOLS */
1599 lstrcpyA(buf, "foo");
1600 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1601 lower_case, -1, buf, sizeof(buf));
1602 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1603 lstrlenA(symbols_stripped) + 1, ret);
1604 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1606 /* test srclen = 0 */
1607 SetLastError(0xdeadbeef);
1608 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1609 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1610 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1611 "unexpected error code %d\n", GetLastError());
1614 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1616 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1619 WCHAR buf[256], buf2[256];
1620 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1622 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1623 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1625 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1628 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1629 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1630 func_name, GetLastError());
1633 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1634 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1635 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1636 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1637 func_name, GetLastError());
1639 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1640 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1641 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1642 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1643 func_name, GetLastError());
1645 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1646 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1647 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1649 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1650 func_name, GetLastError());
1652 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1653 SetLastError(0xdeadbeef);
1654 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1655 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1656 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1657 func_name, GetLastError());
1658 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1660 /* test LCMAP_LOWERCASE */
1661 ret = func_ptr(LCMAP_LOWERCASE,
1662 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1663 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1664 ret, GetLastError(), lstrlenW(upper_case) + 1);
1665 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1667 /* test LCMAP_UPPERCASE */
1668 ret = func_ptr(LCMAP_UPPERCASE,
1669 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1670 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1671 ret, GetLastError(), lstrlenW(lower_case) + 1);
1672 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1674 /* test buffer overflow */
1675 SetLastError(0xdeadbeef);
1676 ret = func_ptr(LCMAP_UPPERCASE,
1677 lower_case, -1, buf, 4);
1678 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1679 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1681 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1682 lstrcpyW(buf, lower_case);
1683 ret = func_ptr(LCMAP_UPPERCASE,
1684 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1685 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1686 ret, GetLastError(), lstrlenW(lower_case) + 1);
1687 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1689 lstrcpyW(buf, upper_case);
1690 ret = func_ptr(LCMAP_LOWERCASE,
1691 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1692 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1693 ret, GetLastError(), lstrlenW(lower_case) + 1);
1694 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1696 /* otherwise src == dst should fail */
1697 SetLastError(0xdeadbeef);
1698 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1699 buf, 10, buf, sizeof(buf));
1700 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1701 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1702 "%s unexpected error code %d\n", func_name, GetLastError());
1703 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1705 /* test whether '\0' is always appended */
1706 ret = func_ptr(LCMAP_SORTKEY,
1707 upper_case, -1, buf, sizeof(buf));
1708 ok(ret, "%s func_ptr must succeed\n", func_name);
1709 ret2 = func_ptr(LCMAP_SORTKEY,
1710 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1711 ok(ret, "%s func_ptr must succeed\n", func_name);
1712 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1713 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1715 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1716 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1717 upper_case, -1, buf, sizeof(buf));
1718 ok(ret, "%s func_ptr must succeed\n", func_name);
1719 ret2 = func_ptr(LCMAP_SORTKEY,
1720 lower_case, -1, buf2, sizeof(buf2));
1721 ok(ret2, "%s func_ptr must succeed\n", func_name);
1722 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1723 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1725 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1726 results from plain LCMAP_SORTKEY on Vista */
1728 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1729 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1730 lower_case, -1, buf, sizeof(buf));
1731 ok(ret, "%s func_ptr must succeed\n", func_name);
1732 ret2 = func_ptr(LCMAP_SORTKEY,
1733 symbols_stripped, -1, buf2, sizeof(buf2));
1734 ok(ret2, "%s func_ptr must succeed\n", func_name);
1735 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1736 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1738 /* test NORM_IGNORENONSPACE */
1739 lstrcpyW(buf, fooW);
1740 ret = func_ptr(NORM_IGNORENONSPACE,
1741 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1742 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1743 lstrlenW(lower_case) + 1, ret);
1744 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1746 /* test NORM_IGNORESYMBOLS */
1747 lstrcpyW(buf, fooW);
1748 ret = func_ptr(NORM_IGNORESYMBOLS,
1749 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1750 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1751 lstrlenW(symbols_stripped) + 1, ret);
1752 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1754 /* test srclen = 0 */
1755 SetLastError(0xdeadbeef);
1756 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1757 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1758 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1759 "%s unexpected error code %d\n", func_name, GetLastError());
1762 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1764 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1767 static void test_LCMapStringW(void)
1772 trace("testing LCMapStringW\n");
1774 SetLastError(0xdeadbeef);
1775 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1777 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1778 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1781 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1784 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1786 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1789 static void test_LCMapStringEx(void)
1792 WCHAR buf[256], badname[] = {'w', 'i', 'n', 'e', 't', 'e', 's', 't', 0};
1794 if (!pLCMapStringEx)
1796 win_skip( "LCMapStringEx not available\n" );
1800 trace("testing LCMapStringEx\n");
1802 SetLastError(0xdeadbeef);
1803 ret = pLCMapStringEx(badname, LCMAP_LOWERCASE,
1804 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1806 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1807 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1810 /* test reserved parameters */
1811 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1812 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1813 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1814 ret, GetLastError(), lstrlenW(upper_case) + 1);
1815 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1817 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1818 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1819 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1820 ret, GetLastError(), lstrlenW(upper_case) + 1);
1821 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1823 /* crashes on native */
1825 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1826 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1828 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1831 struct neutralsublang_name_t {
1837 static const struct neutralsublang_name_t neutralsublang_names[] = {
1838 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1839 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1840 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1841 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1842 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1843 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1844 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1845 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1846 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1847 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1848 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1849 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1850 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1851 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1855 static void test_LocaleNameToLCID(void)
1859 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1860 static const WCHAR enW[] = {'e','n',0};
1862 if (!pLocaleNameToLCID)
1864 win_skip( "LocaleNameToLCID not available\n" );
1870 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1871 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1872 "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1873 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1874 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1875 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1878 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1879 todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1880 "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1881 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1882 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1883 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1886 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1887 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1888 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1889 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1890 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1892 /* english neutral name */
1893 lcid = pLocaleNameToLCID(enW, 0);
1894 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1895 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1898 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1902 lcid = pLocaleNameToLCID(ptr->name, 0);
1905 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1906 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1908 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1909 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1915 /* this requires collation table patch to make it MS compatible */
1916 static const char * const strings_sorted[] =
1948 static const char * const strings[] =
1980 static int compare_string1(const void *e1, const void *e2)
1982 const char *s1 = *(const char *const *)e1;
1983 const char *s2 = *(const char *const *)e2;
1985 return lstrcmpA(s1, s2);
1988 static int compare_string2(const void *e1, const void *e2)
1990 const char *s1 = *(const char *const *)e1;
1991 const char *s2 = *(const char *const *)e2;
1993 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1996 static int compare_string3(const void *e1, const void *e2)
1998 const char *s1 = *(const char *const *)e1;
1999 const char *s2 = *(const char *const *)e2;
2000 char key1[256], key2[256];
2002 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2003 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2004 return strcmp(key1, key2);
2007 static void test_sorting(void)
2010 char **str_buf = (char **)buf;
2013 assert(sizeof(buf) >= sizeof(strings));
2015 /* 1. sort using lstrcmpA */
2016 memcpy(buf, strings, sizeof(strings));
2017 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2018 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2020 ok(!strcmp(strings_sorted[i], str_buf[i]),
2021 "qsort using lstrcmpA failed for element %d\n", i);
2023 /* 2. sort using CompareStringA */
2024 memcpy(buf, strings, sizeof(strings));
2025 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2026 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2028 ok(!strcmp(strings_sorted[i], str_buf[i]),
2029 "qsort using CompareStringA failed for element %d\n", i);
2031 /* 3. sort using sort keys */
2032 memcpy(buf, strings, sizeof(strings));
2033 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2034 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2036 ok(!strcmp(strings_sorted[i], str_buf[i]),
2037 "qsort using sort keys failed for element %d\n", i);
2041 static void test_FoldStringA(void)
2045 char src[256], dst[256];
2046 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2047 static const char digits_dst[] = { '1','2','3','\0' };
2048 static const char composite_src[] =
2050 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2051 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2052 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2053 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2054 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2055 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2056 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2057 0xfb,0xfc,0xfd,0xff,'\0'
2059 static const char composite_dst[] =
2061 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2062 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2063 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2064 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2065 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2066 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2067 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2068 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2069 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2070 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2071 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2072 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2073 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2074 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2075 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2077 static const char composite_dst_alt[] =
2079 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2080 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2081 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2082 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2083 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2084 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2085 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2086 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2087 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2088 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2089 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2090 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2091 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2092 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2093 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2095 static const char ligatures_src[] =
2097 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2099 static const char ligatures_dst[] =
2101 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2103 static const struct special
2107 } foldczone_special[] =
2110 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2111 { 0x98, { 0x20, 0x7e, 0x00 } },
2112 { 0x99, { 0x54, 0x4d, 0x00 } },
2113 { 0xa0, { 0x20, 0x00 } },
2114 { 0xa8, { 0x20, 0xa8, 0x00 } },
2115 { 0xaa, { 0x61, 0x00 } },
2116 { 0xaf, { 0x20, 0xaf, 0x00 } },
2117 { 0xb2, { 0x32, 0x00 } },
2118 { 0xb3, { 0x33, 0x00 } },
2119 { 0xb4, { 0x20, 0xb4, 0x00 } },
2120 { 0xb8, { 0x20, 0xb8, 0x00 } },
2121 { 0xb9, { 0x31, 0x00 } },
2122 { 0xba, { 0x6f, 0x00 } },
2123 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2124 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2125 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2130 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2132 /* these tests are locale specific */
2133 if (GetACP() != 1252)
2135 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2139 /* MAP_FOLDDIGITS */
2141 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2142 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2144 win_skip("FoldStringA is not implemented\n");
2147 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2148 ok(strcmp(dst, digits_dst) == 0,
2149 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2150 for (i = 1; i < 256; i++)
2152 if (!strchr(digits_src, i))
2157 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2158 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2159 ok(dst[0] == src[0],
2160 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2164 /* MAP_EXPAND_LIGATURES */
2166 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2167 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2168 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2169 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2170 ok(strcmp(dst, ligatures_dst) == 0,
2171 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2172 for (i = 1; i < 256; i++)
2174 if (!strchr(ligatures_src, i))
2179 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2183 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2184 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2185 "Got %s for %d\n", dst, i);
2189 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2190 ok(dst[0] == src[0],
2191 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2199 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2200 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2201 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2202 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2203 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2205 for (i = 1; i < 256; i++)
2207 if (!strchr(composite_src, i))
2212 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2213 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2214 ok(dst[0] == src[0],
2215 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2216 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2221 for (i = 1; i < 256; i++)
2226 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2228 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2230 if (foldczone_special[j].src == src[0])
2232 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2233 "Expected ret == 2 or %d, got %d, error %d\n",
2234 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2235 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2236 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2237 (unsigned char)src[0]);
2243 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2244 ok(src[0] == dst[0],
2245 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2246 (unsigned char)src[0], (unsigned char)dst[0]);
2250 /* MAP_PRECOMPOSED */
2251 for (i = 1; i < 256; i++)
2256 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2257 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2258 ok(src[0] == dst[0],
2259 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2260 (unsigned char)src[0], (unsigned char)dst[0]);
2264 static void test_FoldStringW(void)
2268 WCHAR src[256], dst[256], ch, prev_ch = 1;
2269 static const DWORD badFlags[] =
2272 MAP_PRECOMPOSED|MAP_COMPOSITE,
2273 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2274 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2276 /* Ranges of digits 0-9 : Must be sorted! */
2277 static const WCHAR digitRanges[] =
2279 0x0030, /* '0'-'9' */
2280 0x0660, /* Eastern Arabic */
2281 0x06F0, /* Arabic - Hindu */
2282 0x0966, /* Devengari */
2283 0x09E6, /* Bengalii */
2284 0x0A66, /* Gurmukhi */
2285 0x0AE6, /* Gujarati */
2287 0x0BE6, /* Tamil - No 0 */
2288 0x0C66, /* Telugu */
2289 0x0CE6, /* Kannada */
2290 0x0D66, /* Maylayalam */
2293 0x0F29, /* Tibet - 0 is out of sequence */
2294 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2295 0x2080, /* Subscript */
2296 0x245F, /* Circled - 0 is out of sequence */
2297 0x2473, /* Bracketed */
2298 0x2487, /* Full stop */
2299 0x2775, /* Inverted circled - No 0 */
2300 0x277F, /* Patterned circled - No 0 */
2301 0x2789, /* Inverted Patterned circled - No 0 */
2302 0x3020, /* Hangzhou */
2303 0xff10, /* Pliene chasse (?) */
2304 0xffff /* Terminator */
2306 /* Digits which are represented, but out of sequence */
2307 static const WCHAR outOfSequenceDigits[] =
2309 0xB9, /* Superscript 1 */
2310 0xB2, /* Superscript 2 */
2311 0xB3, /* Superscript 3 */
2312 0x0F33, /* Tibetan half zero */
2313 0x24EA, /* Circled 0 */
2314 0x3007, /* Ideographic number zero */
2315 '\0' /* Terminator */
2317 /* Digits in digitRanges for which no representation is available */
2318 static const WCHAR noDigitAvailable[] =
2320 0x0BE6, /* No Tamil 0 */
2321 0x0F29, /* No Tibetan half zero (out of sequence) */
2322 0x2473, /* No Bracketed 0 */
2323 0x2487, /* No 0 Full stop */
2324 0x2775, /* No inverted circled 0 */
2325 0x277F, /* No patterned circled */
2326 0x2789, /* No inverted Patterned circled */
2327 0x3020, /* No Hangzhou 0 */
2328 '\0' /* Terminator */
2330 static const WCHAR foldczone_src[] =
2332 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2333 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2335 static const WCHAR foldczone_dst[] =
2337 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2339 static const WCHAR foldczone_todo_src[] =
2341 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2343 static const WCHAR foldczone_todo_dst[] =
2345 0x3cb,0x1f0,' ','a',0
2347 static const WCHAR foldczone_todo_broken_dst[] =
2349 0x3cb,0x1f0,0xa0,0xaa,0
2351 static const WCHAR ligatures_src[] =
2353 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2354 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2355 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2356 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2357 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2358 0xfb04, 0xfb05, 0xfb06, '\0'
2360 static const WCHAR ligatures_dst[] =
2362 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2363 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2364 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2365 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2366 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2367 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2372 win_skip("FoldStringW is not available\n");
2373 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2376 /* Invalid flag combinations */
2377 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2379 src[0] = dst[0] = '\0';
2381 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2382 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2384 win_skip("FoldStringW is not implemented\n");
2387 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2388 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2391 /* src & dst cannot be the same */
2393 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2394 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2395 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2397 /* src can't be NULL */
2399 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2400 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2401 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2403 /* srclen can't be 0 */
2405 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2406 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2407 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2409 /* dstlen can't be < 0 */
2411 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2412 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2413 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2415 /* Ret includes terminating NUL which is appended if srclen = -1 */
2420 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2421 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2422 ok(dst[0] == 'A' && dst[1] == '\0',
2423 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2424 'A', '\0', ret, dst[0], dst[1], GetLastError());
2426 /* If size is given, result is not NUL terminated */
2432 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2433 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2434 ok(dst[0] == 'A' && dst[1] == 'X',
2435 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2436 'A','X', ret, dst[0], dst[1], GetLastError());
2438 /* MAP_FOLDDIGITS */
2439 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2441 /* Check everything before this range */
2442 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2446 src[1] = dst[0] = '\0';
2447 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2448 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2450 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2451 /* Wine (correctly) maps all Unicode 4.0+ digits */
2452 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2453 (ch >= 0x1369 && ch <= 0x1371),
2454 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2457 if (digitRanges[j] == 0xffff)
2458 break; /* Finished the whole code point space */
2460 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2464 /* Map out of sequence characters */
2465 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2466 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2467 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2468 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2472 src[1] = dst[0] = '\0';
2473 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2474 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2476 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2477 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2478 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2479 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2480 strchrW(noDigitAvailable, c),
2481 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2482 ch, '0' + digitRanges[j] - ch, dst[0]);
2489 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2490 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2491 "Got %d, error %d\n", ret, GetLastError());
2492 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2493 "MAP_FOLDCZONE: Expanded incorrectly\n");
2495 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2496 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2497 "Got %d, error %d\n", ret, GetLastError());
2498 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2499 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2500 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2502 /* MAP_EXPAND_LIGATURES */
2504 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2505 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2506 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2507 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2508 "Got %d, error %d\n", ret, GetLastError());
2509 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2510 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2513 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2518 #define LCID_OK(l) \
2519 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2520 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2521 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2522 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2523 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2525 static void test_ConvertDefaultLocale(void)
2529 /* Doesn't change lcid, even if non default sublang/sort used */
2530 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2531 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2532 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2533 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2535 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2536 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2537 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2538 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2539 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2541 /* Invariant language is not treated specially */
2542 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2544 /* User/system default languages alone are not mapped */
2545 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2546 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2549 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2550 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2551 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2554 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2555 DWORD dwFlags, LONG_PTR lParam)
2557 trace("%08x, %s, %s, %08x, %08lx\n",
2558 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2560 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2561 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2563 /* If lParam is one, we are calling with flags defaulted from 0 */
2564 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2565 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2570 static void test_EnumSystemLanguageGroupsA(void)
2574 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2576 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2580 /* No enumeration proc */
2582 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2583 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2585 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2588 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2589 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2593 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2594 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2596 /* No flags - defaults to LGRPID_INSTALLED */
2597 SetLastError(0xdeadbeef);
2598 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2599 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2601 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2602 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2605 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2607 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2611 static void test_EnumSystemLocalesEx(void)
2615 if (!pEnumSystemLocalesEx)
2617 win_skip( "EnumSystemLocalesEx not available\n" );
2620 SetLastError( 0xdeadbeef );
2621 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2622 ok( !ret, "should have failed\n" );
2623 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2624 SetLastError( 0xdeadbeef );
2625 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2626 ok( ret, "failed err %u\n", GetLastError() );
2629 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2632 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2634 /* invalid locale enumerated on some platforms */
2638 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2639 "Enumerated grp %d not valid\n", lgrpid);
2640 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2641 "Enumerated grp locale %d not valid\n", lcid);
2645 static void test_EnumLanguageGroupLocalesA(void)
2649 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2651 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2655 /* No enumeration proc */
2657 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2658 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2660 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2663 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2664 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2666 /* lgrpid too small */
2668 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2669 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2670 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2672 /* lgrpid too big */
2674 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2675 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2676 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2678 /* dwFlags is reserved */
2680 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2681 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2682 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2684 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2687 static void test_SetLocaleInfoA(void)
2690 LCID lcid = GetUserDefaultLCID();
2694 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2695 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2696 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2700 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2701 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2702 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2706 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2707 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2708 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2711 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2713 trace("%s %08lx\n", value, lParam);
2717 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2719 ok(!enumCount, "callback called again unexpected\n");
2724 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2726 ok(0,"callback called unexpected\n");
2730 static void test_EnumUILanguageA(void)
2733 if (!pEnumUILanguagesA) {
2734 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2738 SetLastError(ERROR_SUCCESS);
2739 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2740 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2742 win_skip("EnumUILanguagesA is not implemented\n");
2745 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2748 SetLastError(ERROR_SUCCESS);
2749 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2750 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2752 SetLastError(ERROR_SUCCESS);
2753 ret = pEnumUILanguagesA(NULL, 0, 0);
2754 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2755 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2756 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2758 SetLastError(ERROR_SUCCESS);
2759 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2760 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2761 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2763 SetLastError(ERROR_SUCCESS);
2764 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 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());
2770 static char date_fmt_buf[1024];
2772 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2774 lstrcatA(date_fmt_buf, fmt);
2775 lstrcatA(date_fmt_buf, "\n");
2779 static void test_EnumDateFormatsA(void)
2783 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2785 trace("EnumDateFormatsA 0\n");
2786 date_fmt_buf[0] = 0;
2787 SetLastError(0xdeadbeef);
2788 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2789 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2791 win_skip("0 for dwFlags is not supported\n");
2795 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2796 trace("%s\n", date_fmt_buf);
2797 /* test the 1st enumerated format */
2798 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2799 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2800 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2801 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2804 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2805 date_fmt_buf[0] = 0;
2806 SetLastError(0xdeadbeef);
2807 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2808 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2810 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2814 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2815 trace("%s\n", date_fmt_buf);
2816 /* test the 1st enumerated format */
2817 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2818 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2819 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2820 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2823 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2824 date_fmt_buf[0] = 0;
2825 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2826 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2827 trace("%s\n", date_fmt_buf);
2828 /* test the 1st enumerated format */
2829 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2830 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2831 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2832 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2834 trace("EnumDateFormatsA DATE_LONGDATE\n");
2835 date_fmt_buf[0] = 0;
2836 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2837 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) 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_SLONGDATE, buf, sizeof(buf));
2842 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2843 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2845 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2846 date_fmt_buf[0] = 0;
2847 SetLastError(0xdeadbeef);
2848 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2849 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2851 skip("DATE_YEARMONTH is only present on W2K and later\n");
2854 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2855 trace("%s\n", date_fmt_buf);
2856 /* test the 1st enumerated format */
2857 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2858 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2859 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2860 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2861 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2864 static void test_EnumTimeFormatsA(void)
2868 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2870 trace("EnumTimeFormatsA 0\n");
2871 date_fmt_buf[0] = 0;
2872 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2873 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2874 trace("%s\n", date_fmt_buf);
2875 /* test the 1st enumerated format */
2876 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2877 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2878 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2879 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2881 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2882 date_fmt_buf[0] = 0;
2883 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2884 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) 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);
2893 static void test_GetCPInfo(void)
2898 SetLastError(0xdeadbeef);
2899 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2900 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2901 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2902 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2904 SetLastError(0xdeadbeef);
2905 ret = GetCPInfo(CP_UTF7, &cpinfo);
2906 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2908 skip("Codepage CP_UTF7 is not installed/available\n");
2912 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2913 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2914 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2915 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2916 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2917 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2920 SetLastError(0xdeadbeef);
2921 ret = GetCPInfo(CP_UTF8, &cpinfo);
2922 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2924 skip("Codepage CP_UTF8 is not installed/available\n");
2928 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2929 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2930 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2931 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2932 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2933 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2934 "expected 4, got %u\n", cpinfo.MaxCharSize);
2939 * The CT_TYPE1 has varied over windows version.
2940 * The current target for correct behavior is windows 7.
2941 * There was a big shift between windows 2000 (first introduced) and windows Xp
2942 * Most of the old values below are from windows 2000.
2943 * A smaller subset of changes happened between windows Xp and Window vista/7
2945 static void test_GetStringTypeW(void)
2947 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2948 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2949 C1_SPACE | C1_BLANK | C1_DEFINED,
2950 C1_SPACE | C1_BLANK | C1_DEFINED,
2951 C1_SPACE | C1_BLANK | C1_DEFINED,
2952 C1_CNTRL | C1_BLANK | C1_DEFINED};
2953 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2954 C1_SPACE | C1_BLANK,
2955 C1_SPACE | C1_BLANK,
2956 C1_SPACE | C1_BLANK,
2957 C1_SPACE | C1_BLANK};
2959 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2962 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2963 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2964 C1_LOWER | C1_ALPHA,
2965 C1_UPPER | C1_LOWER | C1_ALPHA,
2968 /* Sk, Sk, Mn, So, Me */
2969 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2971 0xffe0, 0xffe9, 0x2153};
2973 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2974 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2975 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2976 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2977 C1_ALPHA | C1_DEFINED,
2978 C1_CNTRL | C1_DEFINED,
2979 C1_PUNCT | C1_DEFINED,
2980 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2981 C1_ALPHA | C1_LOWER | C1_DEFINED,
2982 C1_ALPHA | C1_DEFINED };
2983 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2984 C1_ALPHA | C1_DEFINED,
2985 C1_CNTRL | C1_DEFINED,
2986 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2987 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2988 C1_ALPHA | C1_DEFINED,
2991 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2992 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2994 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2995 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2996 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2997 static const WCHAR lower_special[] = {0x2071, 0x207f};
2998 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2999 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3000 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3001 0xfff9, 0xfffa, 0xfffb};
3002 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3007 memset(types,0,sizeof(types));
3008 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3009 for (i = 0; i < 5; i++)
3010 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]);
3012 memset(types,0,sizeof(types));
3013 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3014 for (i = 0; i < 3; i++)
3015 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]));
3016 memset(types,0,sizeof(types));
3017 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3018 for (i = 0; i < 5; i++)
3019 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3021 memset(types,0,sizeof(types));
3022 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3023 for (i = 0; i < 8; i++)
3024 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);
3026 memset(types,0,sizeof(types));
3027 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3028 for (i = 0; i < 7; i++)
3029 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]);
3031 memset(types,0,sizeof(types));
3032 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3033 for (i = 0; i < 7; i++)
3034 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));
3037 memset(types,0,sizeof(types));
3038 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3039 for (i = 0; i < 12; i++)
3040 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);
3042 memset(types,0,sizeof(types));
3043 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3044 for (i = 0; i < 3; i++)
3045 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);
3047 memset(types,0,sizeof(types));
3048 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3049 for (i = 0; i < 2; i++)
3050 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);
3052 memset(types,0,sizeof(types));
3053 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3054 for (i = 0; i < 20; i++)
3055 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);
3057 memset(types,0,sizeof(types));
3058 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3059 for (i = 0; i < 3; i++)
3060 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 );
3063 static void test_IdnToNameprepUnicode(void)
3069 const WCHAR out[64];
3075 5, {'t','e','s','t',0},
3076 5, {'t','e','s','t',0},
3080 3, {'a',0xe111,'b'},
3082 0, ERROR_INVALID_NAME
3087 0, ERROR_INVALID_NAME
3097 0, ERROR_INVALID_NAME
3100 6, {' ','-','/','[',']',0},
3101 6, {' ','-','/','[',']',0},
3107 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3112 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3114 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3115 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3116 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3120 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3124 { /* Another example of incorrectly working FoldString (composition) */
3132 0, ERROR_NO_UNICODE_TRANSLATION
3137 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3140 5, {'a','.','.','a',0},
3142 0, ERROR_INVALID_NAME
3154 if (!pIdnToNameprepUnicode)
3156 win_skip("IdnToNameprepUnicode is not available\n");
3160 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3161 test_data[0].in_len, NULL, 0);
3162 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3164 SetLastError(0xdeadbeef);
3165 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3166 test_data[1].in_len, NULL, 0);
3167 err = GetLastError();
3168 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3169 ok(err == test_data[1].err, "err = %d\n", err);
3171 SetLastError(0xdeadbeef);
3172 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3173 buf, sizeof(buf)/sizeof(WCHAR));
3174 err = GetLastError();
3175 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3176 ok(err == 0xdeadbeef, "err = %d\n", err);
3178 SetLastError(0xdeadbeef);
3179 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3180 buf, sizeof(buf)/sizeof(WCHAR));
3181 err = GetLastError();
3182 ok(ret == 0, "ret = %d\n", ret);
3183 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3185 SetLastError(0xdeadbeef);
3186 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3187 buf, sizeof(buf)/sizeof(WCHAR));
3188 err = GetLastError();
3189 ok(ret == 0, "ret = %d\n", ret);
3190 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3192 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3193 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3194 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3196 SetLastError(0xdeadbeef);
3197 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3198 err = GetLastError();
3199 ok(ret == 0, "ret = %d\n", ret);
3200 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3202 SetLastError(0xdeadbeef);
3203 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3204 err = GetLastError();
3205 ok(ret == 0, "ret = %d\n", ret);
3206 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3208 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3210 SetLastError(0xdeadbeef);
3211 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3212 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3213 err = GetLastError();
3214 if(!test_data[i].todo) {
3215 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3216 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3217 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3218 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3220 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3221 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3226 static void test_IdnToAscii(void)
3232 const WCHAR out[64];
3237 5, {'T','e','s','t',0},
3238 5, {'T','e','s','t',0},
3242 5, {'T','e',0x017c,'s','t',0},
3243 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3247 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3248 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3253 9, {'x','n','-','-','2','d','a','.',0},
3257 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3258 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3262 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3263 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3264 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3269 8, {'x','n','-','-','6','l','a',0},
3270 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3279 win_skip("IdnToAscii is not available\n");
3283 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3285 SetLastError(0xdeadbeef);
3286 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3287 test_data[i].in_len, buf, sizeof(buf));
3288 err = GetLastError();
3289 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3290 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3291 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3292 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3296 static void test_IdnToUnicode(void)
3302 const WCHAR out[64];
3307 5, {'T','e','s','.',0},
3308 5, {'T','e','s','.',0},
3314 0, ERROR_INVALID_NAME
3317 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3318 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3319 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3320 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3321 0x05d1,0x05e8,0x05d9,0x05ea,0},
3325 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3326 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3327 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3328 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3332 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3333 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3334 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3335 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3337 0, ERROR_INVALID_NAME
3340 8, {'x','n','-','-','6','l','a',0},
3342 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3351 win_skip("IdnToUnicode is not available\n");
3355 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3357 SetLastError(0xdeadbeef);
3358 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3359 test_data[i].in_len, buf, sizeof(buf));
3360 err = GetLastError();
3361 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3362 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3363 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3364 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3368 static void test_GetLocaleInfoEx(void)
3370 static const WCHAR enW[] = {'e','n',0};
3374 if (!pGetLocaleInfoEx)
3376 win_skip("GetLocaleInfoEx not supported\n");
3380 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3381 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3384 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3385 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3386 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3387 static const WCHAR usaW[] = {'U','S','A',0};
3388 static const WCHAR enuW[] = {'E','N','U',0};
3389 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3393 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3395 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3396 ok(ret, "got %d\n", ret);
3397 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3399 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3400 ok(ret, "got %d\n", ret);
3401 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3403 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3404 ok(ret, "got %d\n", ret);
3405 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3407 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3408 ok(ret, "got %d\n", ret);
3409 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3412 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3414 ok(!ret, "got %d\n", ret);
3419 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3422 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3424 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3426 pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3428 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3436 InitFunctionPointers();
3439 test_EnumTimeFormatsA();
3440 test_EnumDateFormatsA();
3441 test_GetLocaleInfoA();
3442 test_GetLocaleInfoW();
3443 test_GetLocaleInfoEx();
3444 test_GetTimeFormatA();
3445 test_GetDateFormatA();
3446 test_GetDateFormatW();
3447 test_GetCurrencyFormatA(); /* Also tests the W version */
3448 test_GetNumberFormatA(); /* Also tests the W version */
3449 test_CompareStringA();
3450 test_LCMapStringA();
3451 test_LCMapStringW();
3452 test_LCMapStringEx();
3453 test_LocaleNameToLCID();
3456 test_ConvertDefaultLocale();
3457 test_EnumSystemLanguageGroupsA();
3458 test_EnumSystemLocalesEx();
3459 test_EnumLanguageGroupLocalesA();
3460 test_SetLocaleInfoA();
3461 test_EnumUILanguageA();
3463 test_GetStringTypeW();
3464 test_IdnToNameprepUnicode();
3466 test_IdnToUnicode();
3467 /* this requires collation table patch to make it MS compatible */
3468 if (0) test_sorting();