kernel32: Return LOCALE_INVARIANT from ConvertDefaultLocale.
[wine.git] / dlls / kernel32 / tests / locale.c
blob51e2b073a0499a16affb5cae99e283d6e6b4418a
1 /*
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
22 * NOTES
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.
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.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 localeW[] = {'e','n','-','U','S',0};
43 static const WCHAR fooW[] = {'f','o','o',0};
44 static const WCHAR emptyW[] = {0};
46 static inline unsigned int strlenW( const WCHAR *str )
48 const WCHAR *s = str;
49 while (*s) s++;
50 return s - str;
53 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
55 if (n <= 0) return 0;
56 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
57 return *str1 - *str2;
60 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
62 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
63 return NULL;
66 static inline BOOL isdigitW( WCHAR wc )
68 WORD type;
69 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
70 return type & C1_DIGIT;
73 /* Some functions are only in later versions of kernel32.dll */
74 static HMODULE hKernel32;
75 static WORD enumCount;
77 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
78 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
79 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
80 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
83 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
84 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
85 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
86 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
87 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
89 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
90 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
93 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
94 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
95 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
96 LPNLSVERSIONINFO, LPVOID, LPARAM);
97 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
98 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
99 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
101 static void InitFunctionPointers(void)
103 hKernel32 = GetModuleHandleA("kernel32");
105 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
106 X(GetTimeFormatEx);
107 X(GetDateFormatEx);
108 X(EnumSystemLanguageGroupsA);
109 X(EnumLanguageGroupLocalesA);
110 X(LocaleNameToLCID);
111 X(LCIDToLocaleName);
112 X(LCMapStringEx);
113 X(FoldStringA);
114 X(FoldStringW);
115 X(IsValidLanguageGroup);
116 X(EnumUILanguagesA);
117 X(EnumSystemLocalesEx);
118 X(IdnToNameprepUnicode);
119 X(IdnToAscii);
120 X(IdnToUnicode);
121 X(GetLocaleInfoEx);
122 X(IsValidLocaleName);
123 X(CompareStringOrdinal);
124 X(CompareStringEx);
125 X(GetGeoInfoA);
126 X(GetGeoInfoW);
127 X(EnumSystemGeoID);
128 #undef X
131 #define eq(received, expected, label, type) \
132 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
133 (label), (received), (expected))
135 #define BUFFER_SIZE 128
136 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
138 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
139 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
140 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
141 "Expected '%s', got '%s'\n", Expected, buffer)
143 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
144 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
145 SetLastError(0xdeadbeef); buffer[0] = '\0'
146 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
147 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
149 #define NUO LOCALE_NOUSEROVERRIDE
151 static void test_GetLocaleInfoA(void)
153 int ret;
154 int len;
155 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
156 char buffer[BUFFER_SIZE];
157 char expected[BUFFER_SIZE];
158 DWORD val;
160 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
162 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
163 ok(ret, "got %d\n", ret);
164 ok(val == lcid, "got 0x%08x\n", val);
166 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
167 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
168 assumes SUBLANG_NEUTRAL for zh */
169 memset(expected, 0, COUNTOF(expected));
170 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
171 SetLastError(0xdeadbeef);
172 memset(buffer, 0, COUNTOF(buffer));
173 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
174 ok((ret == len) && !lstrcmpA(buffer, expected),
175 "got %d with '%s' (expected %d with '%s')\n",
176 ret, buffer, len, expected);
178 memset(expected, 0, COUNTOF(expected));
179 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
180 if (len) {
181 SetLastError(0xdeadbeef);
182 memset(buffer, 0, COUNTOF(buffer));
183 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
184 ok((ret == len) && !lstrcmpA(buffer, expected),
185 "got %d with '%s' (expected %d with '%s')\n",
186 ret, buffer, len, expected);
188 else
189 win_skip("LANG_ARABIC not installed\n");
191 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
192 memset(expected, 0, COUNTOF(expected));
193 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
194 SetLastError(0xdeadbeef);
195 memset(buffer, 0, COUNTOF(buffer));
196 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
197 ok((ret == len) && !lstrcmpA(buffer, expected),
198 "got %d with '%s' (expected %d with '%s')\n",
199 ret, buffer, len, expected);
202 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
203 * partially fill the buffer even if it is too short. See bug 637.
205 SetLastError(0xdeadbeef);
206 memset(buffer, 0, COUNTOF(buffer));
207 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
208 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
210 SetLastError(0xdeadbeef);
211 memset(buffer, 0, COUNTOF(buffer));
212 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
213 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
214 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
215 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
217 SetLastError(0xdeadbeef);
218 memset(buffer, 0, COUNTOF(buffer));
219 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
220 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
221 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
224 struct neutralsublang_name2_t {
225 WCHAR name[3];
226 WCHAR sname[15];
227 LCID lcid;
228 LCID lcid_broken;
229 WCHAR sname_broken[15];
230 int todo;
233 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
234 { {'a','r',0}, {'a','r','-','S','A',0},
235 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
236 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
237 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
238 { {'d','e',0}, {'d','e','-','D','E',0},
239 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
240 { {'e','n',0}, {'e','n','-','U','S',0},
241 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
242 { {'e','s',0}, {'e','s','-','E','S',0},
243 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
244 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
245 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
246 { {'g','a',0}, {'g','a','-','I','E',0},
247 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
248 { {'i','t',0}, {'i','t','-','I','T',0},
249 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
250 { {'m','s',0}, {'m','s','-','M','Y',0},
251 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
252 { {'n','l',0}, {'n','l','-','N','L',0},
253 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
254 { {'p','t',0}, {'p','t','-','B','R',0},
255 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
256 { {'s','r',0}, {'h','r','-','H','R',0},
257 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
258 { {'s','v',0}, {'s','v','-','S','E',0},
259 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
260 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
261 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
262 { {'z','h',0}, {'z','h','-','C','N',0},
263 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
264 { {0} }
267 static void test_GetLocaleInfoW(void)
269 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
270 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
271 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
272 WCHAR bufferW[80], buffer2W[80];
273 CHAR bufferA[80];
274 DWORD val;
275 DWORD ret;
276 INT i;
278 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
279 if (!ret) {
280 win_skip("GetLocaleInfoW() isn't implemented\n");
281 return;
284 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
285 ok(ret, "got %d\n", ret);
286 ok(val == lcid_en, "got 0x%08x\n", val);
288 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
289 if (ret)
291 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
292 'S','t','a','t','e','s',')',0};
293 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
294 static const WCHAR enW[] = {'e','n','-','U','S',0};
295 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
297 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
299 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
300 ok(ret, "got %d\n", ret);
301 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
302 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
304 skip("Non-English locale\n");
306 else
307 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
309 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
310 ok(ret, "got %d\n", ret);
311 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
312 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
314 skip("Non-English locale\n");
316 else
317 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
319 while (*ptr->name)
321 LANGID langid;
322 LCID lcid;
324 /* make neutral lcid */
325 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
326 lcid = MAKELCID(langid, SORT_DEFAULT);
328 val = 0;
329 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
330 if (ptr->todo & 0x1)
332 todo_wine
333 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
334 wine_dbgstr_w(ptr->name), val, ptr->lcid);
336 else
337 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
338 wine_dbgstr_w(ptr->name), val, ptr->lcid);
340 /* now check LOCALE_SNAME */
341 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
342 if (ptr->todo & 0x2)
343 todo_wine
344 ok(!lstrcmpW(bufferW, ptr->sname) ||
345 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
346 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
347 else
348 ok(!lstrcmpW(bufferW, ptr->sname) ||
349 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
350 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
351 ptr++;
354 else
355 win_skip("English neutral locale not supported\n");
357 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
358 if (!ret) {
359 win_skip("LANG_RUSSIAN locale data unavailable\n");
360 return;
362 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
363 bufferW, COUNTOF(bufferW));
364 if (!ret) {
365 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
366 return;
369 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
370 bufferA[0] = 'a';
371 SetLastError(0xdeadbeef);
372 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
373 bufferA, COUNTOF(bufferA));
374 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
375 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
376 ok(GetLastError() == ERROR_INVALID_FLAGS,
377 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
379 bufferW[0] = 'a';
380 SetLastError(0xdeadbeef);
381 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
382 bufferW, COUNTOF(bufferW));
383 ok(ret == 0,
384 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
385 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
386 ok(GetLastError() == ERROR_INVALID_FLAGS,
387 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
389 /* yes, test empty 13 month entry too */
390 for (i = 0; i < 12; i++) {
391 bufferW[0] = 0;
392 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
393 bufferW, COUNTOF(bufferW));
394 ok(ret, "Expected non zero result\n");
395 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
396 ret, lstrlenW(bufferW));
397 buffer2W[0] = 0;
398 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
399 buffer2W, COUNTOF(buffer2W));
400 ok(ret, "Expected non zero result\n");
401 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
402 ret, lstrlenW(buffer2W));
404 ok(lstrcmpW(bufferW, buffer2W) != 0,
405 "Expected genitive name to differ, got the same for month %d\n", i+1);
407 /* for locale without genitive names nominative returned in both cases */
408 bufferW[0] = 0;
409 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
410 bufferW, COUNTOF(bufferW));
411 ok(ret, "Expected non zero result\n");
412 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
413 ret, lstrlenW(bufferW));
414 buffer2W[0] = 0;
415 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
416 buffer2W, COUNTOF(buffer2W));
417 ok(ret, "Expected non zero result\n");
418 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
419 ret, lstrlenW(buffer2W));
421 ok(lstrcmpW(bufferW, buffer2W) == 0,
422 "Expected same names, got different for month %d\n", i+1);
426 static void test_GetTimeFormatA(void)
428 int ret;
429 SYSTEMTIME curtime;
430 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
431 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
433 memset(&curtime, 2, sizeof(SYSTEMTIME));
434 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
435 SetLastError(0xdeadbeef);
436 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
437 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
438 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
440 curtime.wHour = 8;
441 curtime.wMinute = 56;
442 curtime.wSecond = 13;
443 curtime.wMilliseconds = 22;
444 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
445 SetLastError(0xdeadbeef);
446 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
447 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
448 EXPECT_LENA; EXPECT_EQA;
450 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
451 SetLastError(0xdeadbeef);
452 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
453 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
454 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
456 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
457 SetLastError(0xdeadbeef);
458 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
459 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
460 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
462 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
463 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
464 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
465 EXPECT_LENA;
467 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
468 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
469 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
470 EXPECT_LENA; EXPECT_EQA;
472 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
473 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
474 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
475 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
476 "Expected '', got '%s'\n", buffer );
478 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
479 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, 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", "8:56 AM"); /* TIME_NOSECONDS */
484 strcpy(Expected, "8:56 AM");
485 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
486 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
487 EXPECT_LENA; EXPECT_EQA;
489 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
490 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
491 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
492 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
493 "Expected '8.@:56AM', got '%s'\n", buffer );
495 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
496 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
497 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
498 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
499 "Expected '', got '%s'\n", buffer );
501 STRINGSA("t/tt", "A/AM"); /* AM time marker */
502 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
503 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
504 EXPECT_LENA; EXPECT_EQA;
506 curtime.wHour = 13;
507 STRINGSA("t/tt", "P/PM"); /* PM time marker */
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 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
513 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
514 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
515 EXPECT_LENA; EXPECT_EQA;
517 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
518 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
519 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
520 EXPECT_LENA; EXPECT_EQA;
522 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
523 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
525 EXPECT_LENA; EXPECT_EQA;
527 curtime.wHour = 14; /* change this to 14 or 2pm */
528 curtime.wMinute = 5;
529 curtime.wSecond = 3;
530 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 */
531 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
532 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
533 EXPECT_LENA; EXPECT_EQA;
535 curtime.wHour = 0;
536 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
537 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
538 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
539 EXPECT_LENA; EXPECT_EQA;
541 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
542 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
543 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
544 EXPECT_LENA; EXPECT_EQA;
546 /* try to convert formatting strings with more than two letters
547 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
548 * NOTE: We expect any letter for which there is an upper case value
549 * we should see a replacement. For letters that DO NOT have
550 * upper case values we should see NO REPLACEMENT.
552 curtime.wHour = 8;
553 curtime.wMinute = 56;
554 curtime.wSecond = 13;
555 curtime.wMilliseconds = 22;
556 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
557 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
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("h", "text"); /* Don't write to buffer if len is 0 */
563 strcpy(buffer, "text");
564 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
565 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
566 EXPECT_EQA;
568 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
569 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
570 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
571 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
572 EXPECT_LENA; EXPECT_EQA;
574 STRINGSA("'''", "'"); /* invalid quoted string */
575 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
576 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
577 EXPECT_LENA; EXPECT_EQA;
579 /* test that msdn suggested single quotation usage works as expected */
580 STRINGSA("''''", "'"); /* single quote mark */
581 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
582 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
583 EXPECT_LENA; EXPECT_EQA;
585 STRINGSA("''HHHHHH", "08"); /* Normal use */
586 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
587 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
588 EXPECT_LENA; EXPECT_EQA;
590 /* and test for normal use of the single quotation mark */
591 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
592 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
593 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
594 EXPECT_LENA; EXPECT_EQA;
596 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
597 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
598 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
599 EXPECT_LENA; EXPECT_EQA;
601 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
602 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
603 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
604 EXPECT_LENA; EXPECT_EQA;
606 curtime.wHour = 25;
607 STRINGSA("'123'tt", ""); /* Invalid time */
608 SetLastError(0xdeadbeef);
609 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
610 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
611 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
613 curtime.wHour = 12;
614 curtime.wMonth = 60; /* Invalid */
615 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
616 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
617 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
618 EXPECT_LENA; EXPECT_EQA;
621 static void test_GetTimeFormatEx(void)
623 int ret;
624 SYSTEMTIME curtime;
625 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
627 if (!pGetTimeFormatEx)
629 win_skip("GetTimeFormatEx not supported\n");
630 return;
633 memset(&curtime, 2, sizeof(SYSTEMTIME));
634 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
635 SetLastError(0xdeadbeef);
636 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
637 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
638 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
640 curtime.wHour = 8;
641 curtime.wMinute = 56;
642 curtime.wSecond = 13;
643 curtime.wMilliseconds = 22;
644 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
645 SetLastError(0xdeadbeef);
646 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
647 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
648 EXPECT_LENW; EXPECT_EQW;
650 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
651 SetLastError(0xdeadbeef);
652 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
653 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
654 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
656 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
657 SetLastError(0xdeadbeef);
658 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
659 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
660 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
662 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
663 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
664 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
665 EXPECT_LENW;
667 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
668 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
669 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
670 EXPECT_LENW; EXPECT_EQW;
672 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
673 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
674 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
675 EXPECT_LENW; EXPECT_EQW;
677 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
678 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
679 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
680 EXPECT_LENW; EXPECT_EQW;
682 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
683 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
684 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
685 EXPECT_LENW; EXPECT_EQW;
687 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
688 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
689 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
690 EXPECT_LENW; EXPECT_EQW;
692 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
693 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
694 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
695 EXPECT_LENW; EXPECT_EQW;
697 STRINGSW("t/tt", "A/AM"); /* AM time marker */
698 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
699 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
700 EXPECT_LENW; EXPECT_EQW;
702 curtime.wHour = 13;
703 STRINGSW("t/tt", "P/PM"); /* PM time marker */
704 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
705 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
706 EXPECT_LENW; EXPECT_EQW;
708 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
709 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
710 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
711 EXPECT_LENW; EXPECT_EQW;
713 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
714 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
715 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
716 EXPECT_LENW; EXPECT_EQW;
718 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
719 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
720 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
721 EXPECT_LENW; EXPECT_EQW;
723 curtime.wHour = 14; /* change this to 14 or 2pm */
724 curtime.wMinute = 5;
725 curtime.wSecond = 3;
726 STRINGSW("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
727 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
728 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
729 EXPECT_LENW; EXPECT_EQW;
731 curtime.wHour = 0;
732 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
733 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
734 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
735 EXPECT_LENW; EXPECT_EQW;
737 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
738 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
739 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
740 EXPECT_LENW; EXPECT_EQW;
742 /* try to convert formatting strings with more than two letters
743 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
744 * NOTE: We expect any letter for which there is an upper case value
745 * we should see a replacement. For letters that DO NOT have
746 * upper case values we should see NO REPLACEMENT.
748 curtime.wHour = 8;
749 curtime.wMinute = 56;
750 curtime.wSecond = 13;
751 curtime.wMilliseconds = 22;
752 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
753 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
754 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
755 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
756 EXPECT_LENW; EXPECT_EQW;
758 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
759 lstrcpyW(buffer, Expected);
760 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
761 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
762 EXPECT_EQW;
764 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
765 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
766 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
767 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
768 EXPECT_LENW; EXPECT_EQW;
770 STRINGSW("'''", "'"); /* invalid quoted string */
771 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
772 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
773 EXPECT_LENW; EXPECT_EQW;
775 /* test that msdn suggested single quotation usage works as expected */
776 STRINGSW("''''", "'"); /* single quote mark */
777 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
778 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
779 EXPECT_LENW; EXPECT_EQW;
781 STRINGSW("''HHHHHH", "08"); /* Normal use */
782 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
783 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
784 EXPECT_LENW; EXPECT_EQW;
786 /* and test for normal use of the single quotation mark */
787 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
788 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
789 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
790 EXPECT_LENW; EXPECT_EQW;
792 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
793 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
794 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
795 EXPECT_LENW; EXPECT_EQW;
797 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
798 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
799 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
800 EXPECT_LENW; EXPECT_EQW;
802 curtime.wHour = 25;
803 STRINGSW("'123'tt", ""); /* Invalid time */
804 SetLastError(0xdeadbeef);
805 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
806 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
807 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
809 curtime.wHour = 12;
810 curtime.wMonth = 60; /* Invalid */
811 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
812 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
813 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
814 EXPECT_LENW; EXPECT_EQW;
817 static void test_GetDateFormatA(void)
819 int ret;
820 SYSTEMTIME curtime;
821 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
822 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
823 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
824 char Broken[BUFFER_SIZE];
825 char short_day[10], month[10], genitive_month[10];
827 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
828 STRINGSA("ddd',' MMM dd yy","");
829 SetLastError(0xdeadbeef);
830 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
831 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
832 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
834 curtime.wYear = 2002;
835 curtime.wMonth = 5;
836 curtime.wDay = 4;
837 curtime.wDayOfWeek = 3;
838 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
839 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
840 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
841 EXPECT_LENA; EXPECT_EQA;
843 /* Same as above but with LOCALE_NOUSEROVERRIDE */
844 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
845 SetLastError(0xdeadbeef);
846 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
847 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
848 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
849 EXPECT_EQA;
851 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
852 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
853 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
854 EXPECT_LENA; EXPECT_EQA;
856 curtime.wHour = 36; /* Invalid */
857 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
858 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
859 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
860 EXPECT_LENA; EXPECT_EQA;
862 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
863 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
864 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
865 EXPECT_EQA;
867 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
868 SetLastError(0xdeadbeef);
869 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
870 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
871 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
873 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
874 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
875 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
876 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
877 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
879 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
880 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
881 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
882 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
883 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
884 "got an unexpected date string '%s'\n", buffer);
886 /* test for expected DATE_YEARMONTH behavior with null format */
887 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
888 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
889 SetLastError(0xdeadbeef);
890 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
891 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
892 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
893 EXPECT_EQA;
895 /* Test that using invalid DATE_* flags results in the correct error */
896 /* and return values */
897 STRINGSA("m/d/y", ""); /* Invalid flags */
898 SetLastError(0xdeadbeef);
899 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
900 &curtime, input, buffer, COUNTOF(buffer));
901 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
902 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
904 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
905 if (!ret)
907 win_skip("LANG_RUSSIAN locale data unavailable\n");
908 return;
911 /* month part should be in genitive form */
912 strcpy(genitive_month, buffer + 2);
913 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
914 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
915 strcpy(month, buffer);
916 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
918 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
919 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
920 strcpy(short_day, buffer);
922 STRINGSA("dd MMMMddd dd", "");
923 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
924 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
925 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
926 EXPECT_EQA;
928 STRINGSA("MMMMddd dd", "");
929 sprintf(Expected, "%s%s 04", month, short_day);
930 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
931 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
932 EXPECT_EQA;
934 STRINGSA("MMMMddd", "");
935 sprintf(Expected, "%s%s", month, short_day);
936 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
937 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
938 EXPECT_EQA;
940 STRINGSA("MMMMdd", "");
941 sprintf(Expected, "%s04", genitive_month);
942 sprintf(Broken, "%s04", month);
943 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
944 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
945 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
946 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
947 "Expected '%s', got '%s'\n", Expected, buffer);
949 STRINGSA("MMMMdd ddd", "");
950 sprintf(Expected, "%s04 %s", genitive_month, short_day);
951 sprintf(Broken, "%s04 %s", month, short_day);
952 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
953 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
954 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
955 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
956 "Expected '%s', got '%s'\n", Expected, buffer);
958 STRINGSA("dd dddMMMM", "");
959 sprintf(Expected, "04 %s%s", short_day, month);
960 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
961 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
962 EXPECT_EQA;
964 STRINGSA("dd dddMMMM ddd MMMMdd", "");
965 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
966 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
967 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
968 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
969 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
970 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
971 "Expected '%s', got '%s'\n", Expected, buffer);
973 /* with literal part */
974 STRINGSA("ddd',' MMMM dd", "");
975 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
976 sprintf(Broken, "%s, %s 04", short_day, month);
977 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
978 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
979 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
980 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
981 "Expected '%s', got '%s'\n", Expected, buffer);
984 static void test_GetDateFormatEx(void)
986 int ret;
987 SYSTEMTIME curtime;
988 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
990 if (!pGetDateFormatEx)
992 win_skip("GetDateFormatEx not supported\n");
993 return;
996 STRINGSW("",""); /* If flags are set, then format must be NULL */
997 SetLastError(0xdeadbeef);
998 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
999 input, buffer, COUNTOF(buffer), NULL);
1000 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1001 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1002 EXPECT_EQW;
1004 STRINGSW("",""); /* NULL buffer, len > 0 */
1005 SetLastError(0xdeadbeef);
1006 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1007 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1008 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1010 STRINGSW("",""); /* NULL buffer, len == 0 */
1011 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1012 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1013 EXPECT_LENW; EXPECT_EQW;
1015 STRINGSW("",""); /* Invalid flag combination */
1016 SetLastError(0xdeadbeef);
1017 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1018 input, NULL, 0, NULL);
1019 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1020 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1021 EXPECT_EQW;
1023 curtime.wYear = 2002;
1024 curtime.wMonth = 10;
1025 curtime.wDay = 23;
1026 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1027 curtime.wHour = 65432; /* Invalid */
1028 curtime.wMinute = 34512; /* Invalid */
1029 curtime.wSecond = 65535; /* Invalid */
1030 curtime.wMilliseconds = 12345;
1031 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1032 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1033 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1034 EXPECT_LENW; EXPECT_EQW;
1036 curtime.wYear = 2002;
1037 curtime.wMonth = 10;
1038 curtime.wDay = 23;
1039 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1040 curtime.wHour = 65432; /* Invalid */
1041 curtime.wMinute = 34512; /* Invalid */
1042 curtime.wSecond = 65535; /* Invalid */
1043 curtime.wMilliseconds = 12345;
1044 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1045 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1046 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1047 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1049 /* Limit tests */
1051 curtime.wYear = 1601;
1052 curtime.wMonth = 1;
1053 curtime.wDay = 1;
1054 curtime.wDayOfWeek = 0; /* Irrelevant */
1055 curtime.wHour = 0;
1056 curtime.wMinute = 0;
1057 curtime.wSecond = 0;
1058 curtime.wMilliseconds = 0;
1059 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1060 SetLastError(0xdeadbeef);
1061 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1062 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1063 EXPECT_LENW; EXPECT_EQW;
1065 curtime.wYear = 1600;
1066 curtime.wMonth = 12;
1067 curtime.wDay = 31;
1068 curtime.wDayOfWeek = 0; /* Irrelevant */
1069 curtime.wHour = 23;
1070 curtime.wMinute = 59;
1071 curtime.wSecond = 59;
1072 curtime.wMilliseconds = 999;
1073 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1074 SetLastError(0xdeadbeef);
1075 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1076 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1077 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1080 static void test_GetDateFormatW(void)
1082 int ret;
1083 SYSTEMTIME curtime;
1084 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1085 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1087 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1088 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1089 input, buffer, COUNTOF(buffer));
1090 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1092 win_skip("GetDateFormatW is not implemented\n");
1093 return;
1095 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1096 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1097 EXPECT_EQW;
1099 STRINGSW("",""); /* NULL buffer, len > 0 */
1100 SetLastError(0xdeadbeef);
1101 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1102 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1103 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1105 STRINGSW("",""); /* NULL buffer, len == 0 */
1106 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1107 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1108 EXPECT_LENW; EXPECT_EQW;
1110 curtime.wYear = 2002;
1111 curtime.wMonth = 10;
1112 curtime.wDay = 23;
1113 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1114 curtime.wHour = 65432; /* Invalid */
1115 curtime.wMinute = 34512; /* Invalid */
1116 curtime.wSecond = 65535; /* Invalid */
1117 curtime.wMilliseconds = 12345;
1118 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1119 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1120 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1121 EXPECT_LENW; EXPECT_EQW;
1123 /* Limit tests */
1125 curtime.wYear = 1601;
1126 curtime.wMonth = 1;
1127 curtime.wDay = 1;
1128 curtime.wDayOfWeek = 0; /* Irrelevant */
1129 curtime.wHour = 0;
1130 curtime.wMinute = 0;
1131 curtime.wSecond = 0;
1132 curtime.wMilliseconds = 0;
1133 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1134 SetLastError(0xdeadbeef);
1135 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1136 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1137 EXPECT_LENW; EXPECT_EQW;
1139 curtime.wYear = 1600;
1140 curtime.wMonth = 12;
1141 curtime.wDay = 31;
1142 curtime.wDayOfWeek = 0; /* Irrelevant */
1143 curtime.wHour = 23;
1144 curtime.wMinute = 59;
1145 curtime.wSecond = 59;
1146 curtime.wMilliseconds = 999;
1147 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1148 SetLastError(0xdeadbeef);
1149 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1150 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1151 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1155 #define CY_POS_LEFT 0
1156 #define CY_POS_RIGHT 1
1157 #define CY_POS_LEFT_SPACE 2
1158 #define CY_POS_RIGHT_SPACE 3
1160 static void test_GetCurrencyFormatA(void)
1162 static char szDot[] = { '.', '\0' };
1163 static char szComma[] = { ',', '\0' };
1164 static char szDollar[] = { '$', '\0' };
1165 int ret;
1166 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1167 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1168 CURRENCYFMTA format;
1170 memset(&format, 0, sizeof(format));
1172 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1173 SetLastError(0xdeadbeef);
1174 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1175 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1176 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1178 STRINGSA("23,53",""); /* Invalid character --> Error */
1179 SetLastError(0xdeadbeef);
1180 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1181 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1182 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1184 STRINGSA("--",""); /* Double '-' --> Error */
1185 SetLastError(0xdeadbeef);
1186 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1187 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1188 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1190 STRINGSA("0-",""); /* Trailing '-' --> Error */
1191 SetLastError(0xdeadbeef);
1192 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1193 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1194 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1196 STRINGSA("0..",""); /* Double '.' --> Error */
1197 SetLastError(0xdeadbeef);
1198 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1199 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1200 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1202 STRINGSA(" 0.1",""); /* Leading space --> Error */
1203 SetLastError(0xdeadbeef);
1204 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1205 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1206 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1208 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1209 SetLastError(0xdeadbeef);
1210 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1211 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1212 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1214 STRINGSA("2353",""); /* Format and flags given --> Error */
1215 SetLastError(0xdeadbeef);
1216 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1217 ok( !ret, "Expected ret == 0, got %d\n", ret);
1218 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1219 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1221 STRINGSA("2353",""); /* Invalid format --> Error */
1222 SetLastError(0xdeadbeef);
1223 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1224 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1225 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1227 STRINGSA("2353","$2,353.00"); /* Valid number */
1228 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1229 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1230 EXPECT_LENA; EXPECT_EQA;
1232 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1233 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1234 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1235 EXPECT_LENA; EXPECT_EQA;
1237 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1238 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1239 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1240 EXPECT_LENA; EXPECT_EQA;
1242 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1243 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1244 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1245 EXPECT_LENA; EXPECT_EQA;
1247 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1248 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1249 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1250 EXPECT_LENA; EXPECT_EQA;
1252 format.NumDigits = 0; /* No decimal separator */
1253 format.LeadingZero = 0;
1254 format.Grouping = 0; /* No grouping char */
1255 format.NegativeOrder = 0;
1256 format.PositiveOrder = CY_POS_LEFT;
1257 format.lpDecimalSep = szDot;
1258 format.lpThousandSep = szComma;
1259 format.lpCurrencySymbol = szDollar;
1261 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1262 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1263 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1264 EXPECT_LENA; EXPECT_EQA;
1266 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1267 STRINGSA("2353","$2353.0");
1268 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1269 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1270 EXPECT_LENA; EXPECT_EQA;
1272 format.Grouping = 2; /* Group by 100's */
1273 STRINGSA("2353","$23,53.0");
1274 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1275 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1276 EXPECT_LENA; EXPECT_EQA;
1278 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1279 format.Grouping = 3;
1280 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1281 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1282 EXPECT_LENA; EXPECT_EQA;
1284 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1285 format.NegativeOrder = 2;
1286 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1287 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1288 EXPECT_LENA; EXPECT_EQA;
1290 format.LeadingZero = 1; /* Always provide leading zero */
1291 STRINGSA(".5","$0.5");
1292 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1293 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1294 EXPECT_LENA; EXPECT_EQA;
1296 format.PositiveOrder = CY_POS_RIGHT;
1297 STRINGSA("1","1.0$");
1298 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1299 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1300 EXPECT_LENA; EXPECT_EQA;
1302 format.PositiveOrder = CY_POS_LEFT_SPACE;
1303 STRINGSA("1","$ 1.0");
1304 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1305 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1306 EXPECT_LENA; EXPECT_EQA;
1308 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1309 STRINGSA("1","1.0 $");
1310 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1311 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1312 EXPECT_LENA; EXPECT_EQA;
1314 format.NegativeOrder = 0;
1315 STRINGSA("-1","($1.0)");
1316 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1317 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1318 EXPECT_LENA; EXPECT_EQA;
1320 format.NegativeOrder = 1;
1321 STRINGSA("-1","-$1.0");
1322 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1323 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1324 EXPECT_LENA; EXPECT_EQA;
1326 format.NegativeOrder = 2;
1327 STRINGSA("-1","$-1.0");
1328 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1329 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1330 EXPECT_LENA; EXPECT_EQA;
1332 format.NegativeOrder = 3;
1333 STRINGSA("-1","$1.0-");
1334 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1335 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1336 EXPECT_LENA; EXPECT_EQA;
1338 format.NegativeOrder = 4;
1339 STRINGSA("-1","(1.0$)");
1340 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1341 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1342 EXPECT_LENA; EXPECT_EQA;
1344 format.NegativeOrder = 5;
1345 STRINGSA("-1","-1.0$");
1346 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1347 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1348 EXPECT_LENA; EXPECT_EQA;
1350 format.NegativeOrder = 6;
1351 STRINGSA("-1","1.0-$");
1352 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1353 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1354 EXPECT_LENA; EXPECT_EQA;
1356 format.NegativeOrder = 7;
1357 STRINGSA("-1","1.0$-");
1358 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1359 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1360 EXPECT_LENA; EXPECT_EQA;
1362 format.NegativeOrder = 8;
1363 STRINGSA("-1","-1.0 $");
1364 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1365 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1366 EXPECT_LENA; EXPECT_EQA;
1368 format.NegativeOrder = 9;
1369 STRINGSA("-1","-$ 1.0");
1370 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1371 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1372 EXPECT_LENA; EXPECT_EQA;
1374 format.NegativeOrder = 10;
1375 STRINGSA("-1","1.0 $-");
1376 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1377 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1378 EXPECT_LENA; EXPECT_EQA;
1380 format.NegativeOrder = 11;
1381 STRINGSA("-1","$ 1.0-");
1382 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1383 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1384 EXPECT_LENA; EXPECT_EQA;
1386 format.NegativeOrder = 12;
1387 STRINGSA("-1","$ -1.0");
1388 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1389 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1390 EXPECT_LENA; EXPECT_EQA;
1392 format.NegativeOrder = 13;
1393 STRINGSA("-1","1.0- $");
1394 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1395 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1396 EXPECT_LENA; EXPECT_EQA;
1398 format.NegativeOrder = 14;
1399 STRINGSA("-1","($ 1.0)");
1400 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1401 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1402 EXPECT_LENA; EXPECT_EQA;
1404 format.NegativeOrder = 15;
1405 STRINGSA("-1","(1.0 $)");
1406 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1407 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1408 EXPECT_LENA; EXPECT_EQA;
1411 #define NEG_PARENS 0 /* "(1.1)" */
1412 #define NEG_LEFT 1 /* "-1.1" */
1413 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1414 #define NEG_RIGHT 3 /* "1.1-" */
1415 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1417 static void test_GetNumberFormatA(void)
1419 static char szDot[] = { '.', '\0' };
1420 static char szComma[] = { ',', '\0' };
1421 int ret;
1422 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1423 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1424 NUMBERFMTA format;
1426 memset(&format, 0, sizeof(format));
1428 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1429 SetLastError(0xdeadbeef);
1430 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1431 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1432 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1434 STRINGSA("23,53",""); /* Invalid character --> Error */
1435 SetLastError(0xdeadbeef);
1436 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1437 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1438 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1440 STRINGSA("--",""); /* Double '-' --> Error */
1441 SetLastError(0xdeadbeef);
1442 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1443 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1444 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1446 STRINGSA("0-",""); /* Trailing '-' --> Error */
1447 SetLastError(0xdeadbeef);
1448 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1449 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1450 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1452 STRINGSA("0..",""); /* Double '.' --> Error */
1453 SetLastError(0xdeadbeef);
1454 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1455 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1456 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1458 STRINGSA(" 0.1",""); /* Leading space --> Error */
1459 SetLastError(0xdeadbeef);
1460 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1461 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1462 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1464 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1465 SetLastError(0xdeadbeef);
1466 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1467 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1468 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1470 STRINGSA("2353",""); /* Format and flags given --> Error */
1471 SetLastError(0xdeadbeef);
1472 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1473 ok( !ret, "Expected ret == 0, got %d\n", ret);
1474 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1475 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1477 STRINGSA("2353",""); /* Invalid format --> Error */
1478 SetLastError(0xdeadbeef);
1479 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1480 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1481 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1483 STRINGSA("2353","2,353.00"); /* Valid number */
1484 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1485 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1486 EXPECT_LENA; EXPECT_EQA;
1488 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1489 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1490 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1491 EXPECT_LENA; EXPECT_EQA;
1493 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1494 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1495 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1496 EXPECT_LENA; EXPECT_EQA;
1498 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1499 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1500 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1501 EXPECT_LENA; EXPECT_EQA;
1503 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1504 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1505 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1506 EXPECT_LENA; EXPECT_EQA;
1508 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1509 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1510 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1511 EXPECT_LENA; EXPECT_EQA;
1513 format.NumDigits = 0; /* No decimal separator */
1514 format.LeadingZero = 0;
1515 format.Grouping = 0; /* No grouping char */
1516 format.NegativeOrder = 0;
1517 format.lpDecimalSep = szDot;
1518 format.lpThousandSep = szComma;
1520 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1521 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1522 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1523 EXPECT_LENA; EXPECT_EQA;
1525 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1526 STRINGSA("2353","2353.0");
1527 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1528 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1529 EXPECT_LENA; EXPECT_EQA;
1531 format.Grouping = 2; /* Group by 100's */
1532 STRINGSA("2353","23,53.0");
1533 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1534 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1535 EXPECT_LENA; EXPECT_EQA;
1537 STRINGSA("235","235.0"); /* Grouping of a positive number */
1538 format.Grouping = 3;
1539 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1540 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1541 EXPECT_LENA; EXPECT_EQA;
1543 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1544 format.NegativeOrder = NEG_LEFT;
1545 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1546 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1547 EXPECT_LENA; EXPECT_EQA;
1549 format.LeadingZero = 1; /* Always provide leading zero */
1550 STRINGSA(".5","0.5");
1551 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1552 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1553 EXPECT_LENA; EXPECT_EQA;
1555 format.NegativeOrder = NEG_PARENS;
1556 STRINGSA("-1","(1.0)");
1557 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1558 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1559 EXPECT_LENA; EXPECT_EQA;
1561 format.NegativeOrder = NEG_LEFT;
1562 STRINGSA("-1","-1.0");
1563 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1564 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1565 EXPECT_LENA; EXPECT_EQA;
1567 format.NegativeOrder = NEG_LEFT_SPACE;
1568 STRINGSA("-1","- 1.0");
1569 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1570 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1571 EXPECT_LENA; EXPECT_EQA;
1573 format.NegativeOrder = NEG_RIGHT;
1574 STRINGSA("-1","1.0-");
1575 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1576 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1577 EXPECT_LENA; EXPECT_EQA;
1579 format.NegativeOrder = NEG_RIGHT_SPACE;
1580 STRINGSA("-1","1.0 -");
1581 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1582 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1583 EXPECT_LENA; EXPECT_EQA;
1585 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1587 if (IsValidLocale(lcid, 0))
1589 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1590 Expected[3] = 160; /* Non breaking space */
1591 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1592 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1593 EXPECT_LENA; EXPECT_EQA;
1597 struct comparestringa_entry {
1598 LCID lcid;
1599 DWORD flags;
1600 const char *first;
1601 int first_len;
1602 const char *second;
1603 int second_len;
1604 int ret;
1607 static const struct comparestringa_entry comparestringa_data[] = {
1608 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1609 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1610 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1611 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1612 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1613 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1614 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1615 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1616 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1617 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1618 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1619 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1620 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1621 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1622 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1623 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1624 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1625 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1626 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1627 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1628 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1629 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1630 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1631 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1632 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1633 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1634 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1635 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1636 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1637 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1640 static void test_CompareStringA(void)
1642 int ret, i;
1643 char a[256];
1644 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1646 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1648 const struct comparestringa_entry *entry = &comparestringa_data[i];
1650 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1651 entry->second, entry->second_len);
1652 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1655 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1656 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1658 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1659 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1661 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1662 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1664 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1665 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1667 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1669 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1670 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1672 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1673 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1675 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1676 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1678 /* test for CompareStringA flags */
1679 SetLastError(0xdeadbeef);
1680 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1681 ok(GetLastError() == ERROR_INVALID_FLAGS,
1682 "unexpected error code %d\n", GetLastError());
1683 ok(!ret, "CompareStringA must fail with invalid flag\n");
1685 SetLastError(0xdeadbeef);
1686 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1687 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1688 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1689 /* end of test for CompareStringA flags */
1691 ret = lstrcmpA("", "");
1692 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1694 ret = lstrcmpA(NULL, NULL);
1695 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1697 ret = lstrcmpA("", NULL);
1698 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1700 ret = lstrcmpA(NULL, "");
1701 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1704 if (0) { /* this requires collation table patch to make it MS compatible */
1705 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1706 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1708 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1709 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1711 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1712 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1714 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1715 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1717 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1718 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1720 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1721 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1723 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1724 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1726 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1727 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1729 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1730 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1732 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1733 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1735 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1736 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1738 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1739 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1743 /* WinXP handles embedded NULLs differently than earlier versions */
1744 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1745 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1747 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1748 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);
1750 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1751 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1753 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1754 ok(ret == CSTR_EQUAL || /* win2k */
1755 ret == CSTR_GREATER_THAN,
1756 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1758 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1759 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1761 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1762 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1764 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1765 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1767 ret = lstrcmpiA("#", ".");
1768 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1770 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1772 /* \xB9 character lies between a and b */
1773 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1774 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1775 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1776 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1778 memset(a, 'a', sizeof(a));
1779 SetLastError(0xdeadbeef);
1780 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1781 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1782 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1785 struct comparestringex_test {
1786 const char *locale;
1787 DWORD flags;
1788 const WCHAR first[2];
1789 const WCHAR second[2];
1790 INT ret;
1791 INT broken;
1792 BOOL todo;
1795 static const struct comparestringex_test comparestringex_tests[] = {
1796 /* default behavior */
1797 { /* 0 */
1798 "tr-TR", 0,
1799 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
1801 { /* 1 */
1802 "tr-TR", 0,
1803 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1805 { /* 2 */
1806 "tr-TR", 0,
1807 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1809 { /* 3 */
1810 "tr-TR", 0,
1811 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1813 { /* 4 */
1814 "tr-TR", 0,
1815 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1817 { /* 5 */
1818 "tr-TR", 0,
1819 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1821 /* with NORM_IGNORECASE */
1822 { /* 6 */
1823 "tr-TR", NORM_IGNORECASE,
1824 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
1826 { /* 7 */
1827 "tr-TR", NORM_IGNORECASE,
1828 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1830 { /* 8 */
1831 "tr-TR", NORM_IGNORECASE,
1832 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1834 { /* 9 */
1835 "tr-TR", NORM_IGNORECASE,
1836 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1838 { /* 10 */
1839 "tr-TR", NORM_IGNORECASE,
1840 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1842 { /* 11 */
1843 "tr-TR", NORM_IGNORECASE,
1844 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1846 /* with NORM_LINGUISTIC_CASING */
1847 { /* 12 */
1848 "tr-TR", NORM_LINGUISTIC_CASING,
1849 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1851 { /* 13 */
1852 "tr-TR", NORM_LINGUISTIC_CASING,
1853 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1855 { /* 14 */
1856 "tr-TR", NORM_LINGUISTIC_CASING,
1857 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1859 { /* 15 */
1860 "tr-TR", NORM_LINGUISTIC_CASING,
1861 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1863 { /* 16 */
1864 "tr-TR", NORM_LINGUISTIC_CASING,
1865 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1867 { /* 17 */
1868 "tr-TR", NORM_LINGUISTIC_CASING,
1869 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1871 /* with LINGUISTIC_IGNORECASE */
1872 { /* 18 */
1873 "tr-TR", LINGUISTIC_IGNORECASE,
1874 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
1876 { /* 19 */
1877 "tr-TR", LINGUISTIC_IGNORECASE,
1878 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1880 { /* 20 */
1881 "tr-TR", LINGUISTIC_IGNORECASE,
1882 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1884 { /* 21 */
1885 "tr-TR", LINGUISTIC_IGNORECASE,
1886 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1888 { /* 22 */
1889 "tr-TR", LINGUISTIC_IGNORECASE,
1890 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1892 { /* 23 */
1893 "tr-TR", LINGUISTIC_IGNORECASE,
1894 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1896 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
1897 { /* 24 */
1898 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1899 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1901 { /* 25 */
1902 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1903 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
1905 { /* 26 */
1906 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1907 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1909 { /* 27 */
1910 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1911 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1913 { /* 28 */
1914 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1915 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1917 { /* 29 */
1918 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1919 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1921 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
1922 { /* 30 */
1923 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1924 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1926 { /* 31 */
1927 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1928 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1930 { /* 32 */
1931 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1932 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1934 { /* 33 */
1935 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1936 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1938 { /* 34 */
1939 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1940 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1942 { /* 35 */
1943 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1944 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1948 static void test_CompareStringEx(void)
1950 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
1951 WCHAR locale[6];
1952 INT ret, i;
1954 /* CompareStringEx is only available on Vista+ */
1955 if (!pCompareStringEx)
1957 win_skip("CompareStringEx not supported\n");
1958 return;
1961 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
1963 const struct comparestringex_test *e = &comparestringex_tests[i];
1965 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
1966 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
1967 if (e->todo)
1969 todo_wine ok(ret == e->ret || broken(ret == e->broken),
1970 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1972 else
1974 ok(ret == e->ret || broken(ret == e->broken),
1975 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1981 static void test_LCMapStringA(void)
1983 int ret, ret2;
1984 char buf[256], buf2[256];
1985 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1986 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1987 static const char symbols_stripped[] = "justateststring1";
1989 SetLastError(0xdeadbeef);
1990 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1991 lower_case, -1, buf, sizeof(buf));
1992 ok(ret == lstrlenA(lower_case) + 1,
1993 "ret %d, error %d, expected value %d\n",
1994 ret, GetLastError(), lstrlenA(lower_case) + 1);
1995 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1997 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1998 upper_case, -1, buf, sizeof(buf));
1999 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2000 ok(GetLastError() == ERROR_INVALID_FLAGS,
2001 "unexpected error code %d\n", GetLastError());
2003 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
2004 upper_case, -1, buf, sizeof(buf));
2005 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
2006 ok(GetLastError() == ERROR_INVALID_FLAGS,
2007 "unexpected error code %d\n", GetLastError());
2009 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2010 upper_case, -1, buf, sizeof(buf));
2011 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
2012 ok(GetLastError() == ERROR_INVALID_FLAGS,
2013 "unexpected error code %d\n", GetLastError());
2015 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2016 upper_case, -1, buf, sizeof(buf));
2017 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
2018 ok(GetLastError() == ERROR_INVALID_FLAGS,
2019 "unexpected error code %d\n", GetLastError());
2021 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2022 SetLastError(0xdeadbeef);
2023 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
2024 upper_case, -1, buf, sizeof(buf));
2025 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2026 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
2028 /* test LCMAP_LOWERCASE */
2029 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2030 upper_case, -1, buf, sizeof(buf));
2031 ok(ret == lstrlenA(upper_case) + 1,
2032 "ret %d, error %d, expected value %d\n",
2033 ret, GetLastError(), lstrlenA(upper_case) + 1);
2034 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2036 /* test LCMAP_UPPERCASE */
2037 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2038 lower_case, -1, buf, sizeof(buf));
2039 ok(ret == lstrlenA(lower_case) + 1,
2040 "ret %d, error %d, expected value %d\n",
2041 ret, GetLastError(), lstrlenA(lower_case) + 1);
2042 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2044 /* test buffer overflow */
2045 SetLastError(0xdeadbeef);
2046 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2047 lower_case, -1, buf, 4);
2048 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2049 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2051 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2052 lstrcpyA(buf, lower_case);
2053 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2054 buf, -1, buf, sizeof(buf));
2055 if (!ret) /* Win9x */
2056 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2057 else
2059 ok(ret == lstrlenA(lower_case) + 1,
2060 "ret %d, error %d, expected value %d\n",
2061 ret, GetLastError(), lstrlenA(lower_case) + 1);
2062 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2064 lstrcpyA(buf, upper_case);
2065 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2066 buf, -1, buf, sizeof(buf));
2067 if (!ret) /* Win9x */
2068 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2069 else
2071 ok(ret == lstrlenA(upper_case) + 1,
2072 "ret %d, error %d, expected value %d\n",
2073 ret, GetLastError(), lstrlenA(lower_case) + 1);
2074 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2077 /* otherwise src == dst should fail */
2078 SetLastError(0xdeadbeef);
2079 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2080 buf, 10, buf, sizeof(buf));
2081 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2082 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2083 "unexpected error code %d\n", GetLastError());
2084 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2086 /* test whether '\0' is always appended */
2087 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2088 upper_case, -1, buf, sizeof(buf));
2089 ok(ret, "LCMapStringA must succeed\n");
2090 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2091 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2092 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2093 ok(ret2, "LCMapStringA must succeed\n");
2094 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2095 ok(ret == ret2, "lengths of sort keys must be equal\n");
2096 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2098 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2099 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2100 upper_case, -1, buf, sizeof(buf));
2101 ok(ret, "LCMapStringA must succeed\n");
2102 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2103 lower_case, -1, buf2, sizeof(buf2));
2104 ok(ret2, "LCMapStringA must succeed\n");
2105 ok(ret == ret2, "lengths of sort keys must be equal\n");
2106 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2108 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2109 results from plain LCMAP_SORTKEY on Vista */
2111 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2112 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2113 lower_case, -1, buf, sizeof(buf));
2114 ok(ret, "LCMapStringA must succeed\n");
2115 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2116 symbols_stripped, -1, buf2, sizeof(buf2));
2117 ok(ret2, "LCMapStringA must succeed\n");
2118 ok(ret == ret2, "lengths of sort keys must be equal\n");
2119 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2121 /* test NORM_IGNORENONSPACE */
2122 lstrcpyA(buf, "foo");
2123 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2124 lower_case, -1, buf, sizeof(buf));
2125 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2126 lstrlenA(lower_case) + 1, ret);
2127 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2129 /* test NORM_IGNORESYMBOLS */
2130 lstrcpyA(buf, "foo");
2131 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2132 lower_case, -1, buf, sizeof(buf));
2133 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2134 lstrlenA(symbols_stripped) + 1, ret);
2135 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2137 /* test srclen = 0 */
2138 SetLastError(0xdeadbeef);
2139 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2140 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2141 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2142 "unexpected error code %d\n", GetLastError());
2145 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2147 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2149 int ret, ret2;
2150 WCHAR buf[256], buf2[256];
2151 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2153 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2154 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2155 if (broken(ret))
2156 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
2157 else
2159 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
2160 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2161 func_name, GetLastError());
2164 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
2165 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2166 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
2167 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2168 func_name, GetLastError());
2170 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2171 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2172 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
2173 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2174 func_name, GetLastError());
2176 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2177 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2178 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
2179 func_name);
2180 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2181 func_name, GetLastError());
2183 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2184 SetLastError(0xdeadbeef);
2185 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
2186 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2187 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
2188 func_name, GetLastError());
2189 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
2191 /* test LCMAP_LOWERCASE */
2192 ret = func_ptr(LCMAP_LOWERCASE,
2193 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2194 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2195 ret, GetLastError(), lstrlenW(upper_case) + 1);
2196 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2198 /* test LCMAP_UPPERCASE */
2199 ret = func_ptr(LCMAP_UPPERCASE,
2200 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2201 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2202 ret, GetLastError(), lstrlenW(lower_case) + 1);
2203 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2205 /* test buffer overflow */
2206 SetLastError(0xdeadbeef);
2207 ret = func_ptr(LCMAP_UPPERCASE,
2208 lower_case, -1, buf, 4);
2209 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2210 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2212 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2213 lstrcpyW(buf, lower_case);
2214 ret = func_ptr(LCMAP_UPPERCASE,
2215 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2216 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2217 ret, GetLastError(), lstrlenW(lower_case) + 1);
2218 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2220 lstrcpyW(buf, upper_case);
2221 ret = func_ptr(LCMAP_LOWERCASE,
2222 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2223 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2224 ret, GetLastError(), lstrlenW(lower_case) + 1);
2225 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2227 /* otherwise src == dst should fail */
2228 SetLastError(0xdeadbeef);
2229 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2230 buf, 10, buf, sizeof(buf));
2231 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2232 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2233 "%s unexpected error code %d\n", func_name, GetLastError());
2234 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2236 /* test whether '\0' is always appended */
2237 ret = func_ptr(LCMAP_SORTKEY,
2238 upper_case, -1, buf, sizeof(buf));
2239 ok(ret, "%s func_ptr must succeed\n", func_name);
2240 ret2 = func_ptr(LCMAP_SORTKEY,
2241 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2242 ok(ret, "%s func_ptr must succeed\n", func_name);
2243 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2244 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2246 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2247 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2248 upper_case, -1, buf, sizeof(buf));
2249 ok(ret, "%s func_ptr must succeed\n", func_name);
2250 ret2 = func_ptr(LCMAP_SORTKEY,
2251 lower_case, -1, buf2, sizeof(buf2));
2252 ok(ret2, "%s func_ptr must succeed\n", func_name);
2253 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2254 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2256 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2257 results from plain LCMAP_SORTKEY on Vista */
2259 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2260 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2261 lower_case, -1, buf, sizeof(buf));
2262 ok(ret, "%s func_ptr must succeed\n", func_name);
2263 ret2 = func_ptr(LCMAP_SORTKEY,
2264 symbols_stripped, -1, buf2, sizeof(buf2));
2265 ok(ret2, "%s func_ptr must succeed\n", func_name);
2266 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2267 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2269 /* test NORM_IGNORENONSPACE */
2270 lstrcpyW(buf, fooW);
2271 ret = func_ptr(NORM_IGNORENONSPACE,
2272 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2273 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2274 lstrlenW(lower_case) + 1, ret);
2275 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2277 /* test NORM_IGNORESYMBOLS */
2278 lstrcpyW(buf, fooW);
2279 ret = func_ptr(NORM_IGNORESYMBOLS,
2280 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2281 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2282 lstrlenW(symbols_stripped) + 1, ret);
2283 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2285 /* test srclen = 0 */
2286 SetLastError(0xdeadbeef);
2287 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2288 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2289 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2290 "%s unexpected error code %d\n", func_name, GetLastError());
2293 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2295 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2298 static void test_LCMapStringW(void)
2300 int ret;
2301 WCHAR buf[256];
2303 trace("testing LCMapStringW\n");
2305 SetLastError(0xdeadbeef);
2306 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2307 todo_wine {
2308 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2309 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2312 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2315 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2317 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2320 static void test_LCMapStringEx(void)
2322 int ret;
2323 WCHAR buf[256];
2325 if (!pLCMapStringEx)
2327 win_skip( "LCMapStringEx not available\n" );
2328 return;
2331 trace("testing LCMapStringEx\n");
2333 SetLastError(0xdeadbeef);
2334 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2335 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2336 todo_wine {
2337 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2338 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2341 /* test reserved parameters */
2342 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2343 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2344 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2345 ret, GetLastError(), lstrlenW(upper_case) + 1);
2346 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2348 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2349 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2350 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2351 ret, GetLastError(), lstrlenW(upper_case) + 1);
2352 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2354 /* crashes on native */
2355 if(0)
2356 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2357 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2359 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2362 struct neutralsublang_name_t {
2363 WCHAR name[3];
2364 LCID lcid;
2365 int todo;
2368 static const struct neutralsublang_name_t neutralsublang_names[] = {
2369 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2370 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2371 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2372 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2373 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2374 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2375 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2376 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2377 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2378 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2379 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2380 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2381 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2382 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2383 { {0} }
2386 static void test_LocaleNameToLCID(void)
2388 LCID lcid;
2389 INT ret;
2390 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2391 static const WCHAR enW[] = {'e','n',0};
2393 if (!pLocaleNameToLCID)
2395 win_skip( "LocaleNameToLCID not available\n" );
2396 return;
2399 /* special cases */
2400 buffer[0] = 0;
2401 SetLastError(0xdeadbeef);
2402 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2403 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2404 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2405 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2406 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2407 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2409 buffer[0] = 0;
2410 SetLastError(0xdeadbeef);
2411 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2412 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2413 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2414 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2415 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2416 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2418 buffer[0] = 0;
2419 SetLastError(0xdeadbeef);
2420 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2421 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2422 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2423 todo_wine ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2424 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2426 /* bad name */
2427 SetLastError(0xdeadbeef);
2428 lcid = pLocaleNameToLCID(fooW, 0);
2429 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2430 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
2432 /* english neutral name */
2433 lcid = pLocaleNameToLCID(enW, 0);
2434 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2435 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2436 if (lcid)
2438 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2440 while (*ptr->name)
2442 lcid = pLocaleNameToLCID(ptr->name, 0);
2443 if (ptr->todo)
2444 todo_wine
2445 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2446 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2447 else
2448 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2449 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2451 *buffer = 0;
2452 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2453 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2454 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2455 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2457 ptr++;
2462 /* this requires collation table patch to make it MS compatible */
2463 static const char * const strings_sorted[] =
2465 "'",
2466 "-",
2467 "!",
2468 "\"",
2469 ".",
2470 ":",
2471 "\\",
2472 "_",
2473 "`",
2474 "{",
2475 "}",
2476 "+",
2477 "0",
2478 "1",
2479 "2",
2480 "3",
2481 "4",
2482 "5",
2483 "6",
2484 "7",
2485 "8",
2486 "9",
2487 "a",
2488 "A",
2489 "b",
2490 "B",
2491 "c",
2495 static const char * const strings[] =
2497 "C",
2498 "\"",
2499 "9",
2500 "'",
2501 "}",
2502 "-",
2503 "7",
2504 "+",
2505 "`",
2506 "1",
2507 "a",
2508 "5",
2509 "\\",
2510 "8",
2511 "B",
2512 "3",
2513 "_",
2514 "6",
2515 "{",
2516 "2",
2517 "c",
2518 "4",
2519 "!",
2520 "0",
2521 "A",
2522 ":",
2523 "b",
2527 static int compare_string1(const void *e1, const void *e2)
2529 const char *s1 = *(const char *const *)e1;
2530 const char *s2 = *(const char *const *)e2;
2532 return lstrcmpA(s1, s2);
2535 static int compare_string2(const void *e1, const void *e2)
2537 const char *s1 = *(const char *const *)e1;
2538 const char *s2 = *(const char *const *)e2;
2540 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2543 static int compare_string3(const void *e1, const void *e2)
2545 const char *s1 = *(const char *const *)e1;
2546 const char *s2 = *(const char *const *)e2;
2547 char key1[256], key2[256];
2549 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2550 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2551 return strcmp(key1, key2);
2554 static void test_sorting(void)
2556 char buf[256];
2557 char **str_buf = (char **)buf;
2558 int i;
2560 assert(sizeof(buf) >= sizeof(strings));
2562 /* 1. sort using lstrcmpA */
2563 memcpy(buf, strings, sizeof(strings));
2564 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2565 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2567 ok(!strcmp(strings_sorted[i], str_buf[i]),
2568 "qsort using lstrcmpA failed for element %d\n", i);
2570 /* 2. sort using CompareStringA */
2571 memcpy(buf, strings, sizeof(strings));
2572 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2573 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2575 ok(!strcmp(strings_sorted[i], str_buf[i]),
2576 "qsort using CompareStringA failed for element %d\n", i);
2578 /* 3. sort using sort keys */
2579 memcpy(buf, strings, sizeof(strings));
2580 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2581 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2583 ok(!strcmp(strings_sorted[i], str_buf[i]),
2584 "qsort using sort keys failed for element %d\n", i);
2588 static void test_FoldStringA(void)
2590 int ret, i, j;
2591 BOOL is_special;
2592 char src[256], dst[256];
2593 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2594 static const char digits_dst[] = { '1','2','3','\0' };
2595 static const char composite_src[] =
2597 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2598 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2599 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2600 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2601 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2602 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2603 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2604 0xfb,0xfc,0xfd,0xff,'\0'
2606 static const char composite_dst[] =
2608 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2609 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2610 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2611 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2612 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2613 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2614 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2615 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2616 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2617 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2618 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2619 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2620 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2621 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2622 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2624 static const char composite_dst_alt[] =
2626 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2627 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2628 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2629 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2630 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2631 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2632 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2633 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2634 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2635 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2636 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2637 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2638 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2639 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2640 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2642 static const char ligatures_src[] =
2644 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2646 static const char ligatures_dst[] =
2648 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2650 static const struct special
2652 char src;
2653 char dst[4];
2654 } foldczone_special[] =
2656 /* src dst */
2657 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2658 { 0x98, { 0x20, 0x7e, 0x00 } },
2659 { 0x99, { 0x54, 0x4d, 0x00 } },
2660 { 0xa0, { 0x20, 0x00 } },
2661 { 0xa8, { 0x20, 0xa8, 0x00 } },
2662 { 0xaa, { 0x61, 0x00 } },
2663 { 0xaf, { 0x20, 0xaf, 0x00 } },
2664 { 0xb2, { 0x32, 0x00 } },
2665 { 0xb3, { 0x33, 0x00 } },
2666 { 0xb4, { 0x20, 0xb4, 0x00 } },
2667 { 0xb8, { 0x20, 0xb8, 0x00 } },
2668 { 0xb9, { 0x31, 0x00 } },
2669 { 0xba, { 0x6f, 0x00 } },
2670 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2671 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2672 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2673 { 0x00 }
2676 if (!pFoldStringA)
2677 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2679 /* these tests are locale specific */
2680 if (GetACP() != 1252)
2682 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2683 return;
2686 /* MAP_FOLDDIGITS */
2687 SetLastError(0);
2688 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2689 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2691 win_skip("FoldStringA is not implemented\n");
2692 return;
2694 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2695 ok(strcmp(dst, digits_dst) == 0,
2696 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2697 for (i = 1; i < 256; i++)
2699 if (!strchr(digits_src, i))
2701 src[0] = i;
2702 src[1] = '\0';
2703 SetLastError(0);
2704 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2705 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2706 ok(dst[0] == src[0],
2707 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2711 /* MAP_EXPAND_LIGATURES */
2712 SetLastError(0);
2713 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2714 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2715 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2716 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2717 ok(strcmp(dst, ligatures_dst) == 0,
2718 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2719 for (i = 1; i < 256; i++)
2721 if (!strchr(ligatures_src, i))
2723 src[0] = i;
2724 src[1] = '\0';
2725 SetLastError(0);
2726 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2727 if (ret == 3)
2729 /* Vista */
2730 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2731 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2732 "Got %s for %d\n", dst, i);
2734 else
2736 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2737 ok(dst[0] == src[0],
2738 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2744 /* MAP_COMPOSITE */
2745 SetLastError(0);
2746 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2747 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2748 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2749 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2750 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2752 for (i = 1; i < 256; i++)
2754 if (!strchr(composite_src, i))
2756 src[0] = i;
2757 src[1] = '\0';
2758 SetLastError(0);
2759 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2760 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2761 ok(dst[0] == src[0],
2762 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2763 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2767 /* MAP_FOLDCZONE */
2768 for (i = 1; i < 256; i++)
2770 src[0] = i;
2771 src[1] = '\0';
2772 SetLastError(0);
2773 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2774 is_special = FALSE;
2775 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2777 if (foldczone_special[j].src == src[0])
2779 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2780 "Expected ret == 2 or %d, got %d, error %d\n",
2781 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2782 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2783 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2784 (unsigned char)src[0]);
2785 is_special = TRUE;
2788 if (! is_special)
2790 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2791 ok(src[0] == dst[0],
2792 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2793 (unsigned char)src[0], (unsigned char)dst[0]);
2797 /* MAP_PRECOMPOSED */
2798 for (i = 1; i < 256; i++)
2800 src[0] = i;
2801 src[1] = '\0';
2802 SetLastError(0);
2803 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2804 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2805 ok(src[0] == dst[0],
2806 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2807 (unsigned char)src[0], (unsigned char)dst[0]);
2811 static void test_FoldStringW(void)
2813 int ret;
2814 unsigned int i, j;
2815 WCHAR src[256], dst[256], ch, prev_ch = 1;
2816 static const DWORD badFlags[] =
2819 MAP_PRECOMPOSED|MAP_COMPOSITE,
2820 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2821 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2823 /* Ranges of digits 0-9 : Must be sorted! */
2824 static const WCHAR digitRanges[] =
2826 0x0030, /* '0'-'9' */
2827 0x0660, /* Eastern Arabic */
2828 0x06F0, /* Arabic - Hindu */
2829 0x07C0, /* Nko */
2830 0x0966, /* Devengari */
2831 0x09E6, /* Bengalii */
2832 0x0A66, /* Gurmukhi */
2833 0x0AE6, /* Gujarati */
2834 0x0B66, /* Oriya */
2835 0x0BE6, /* Tamil - No 0 */
2836 0x0C66, /* Telugu */
2837 0x0CE6, /* Kannada */
2838 0x0D66, /* Maylayalam */
2839 0x0DE6, /* Sinhala Lith */
2840 0x0E50, /* Thai */
2841 0x0ED0, /* Laos */
2842 0x0F20, /* Tibet */
2843 0x0F29, /* Tibet half - 0 is out of sequence */
2844 0x1040, /* Myanmar */
2845 0x1090, /* Myanmar Shan */
2846 0x1368, /* Ethiopic - no 0 */
2847 0x17E0, /* Khmer */
2848 0x1810, /* Mongolian */
2849 0x1946, /* Limbu */
2850 0x19D0, /* New Tai Lue */
2851 0x1A80, /* Tai Tham Hora */
2852 0x1A90, /* Tai Tham Tham */
2853 0x1B50, /* Balinese */
2854 0x1BB0, /* Sundanese */
2855 0x1C40, /* Lepcha */
2856 0x1C50, /* Ol Chiki */
2857 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2858 0x2080, /* Subscript */
2859 0x245F, /* Circled - 0 is out of sequence */
2860 0x2473, /* Bracketed */
2861 0x2487, /* Full stop */
2862 0x24F4, /* Double Circled */
2863 0x2775, /* Inverted circled - No 0 */
2864 0x277F, /* Patterned circled - No 0 */
2865 0x2789, /* Inverted Patterned circled - No 0 */
2866 0x3020, /* Hangzhou */
2867 0xA620, /* Vai */
2868 0xA8D0, /* Saurashtra */
2869 0xA900, /* Kayah Li */
2870 0xA9D0, /* Javanese */
2871 0xA9F0, /* Myanmar Tai Laing */
2872 0xAA50, /* Cham */
2873 0xABF0, /* Meetei Mayek */
2874 0xff10, /* Pliene chasse (?) */
2875 0xffff /* Terminator */
2877 /* Digits which are represented, but out of sequence */
2878 static const WCHAR outOfSequenceDigits[] =
2880 0xB9, /* Superscript 1 */
2881 0xB2, /* Superscript 2 */
2882 0xB3, /* Superscript 3 */
2883 0x0C78, /* Telugu Fraction 0 */
2884 0x0C79, /* Telugu Fraction 1 */
2885 0x0C7A, /* Telugu Fraction 2 */
2886 0x0C7B, /* Telugu Fraction 3 */
2887 0x0C7C, /* Telugu Fraction 1 */
2888 0x0C7D, /* Telugu Fraction 2 */
2889 0x0C7E, /* Telugu Fraction 3 */
2890 0x0F33, /* Tibetan half zero */
2891 0x19DA, /* New Tai Lue Tham 1 */
2892 0x24EA, /* Circled 0 */
2893 0x24FF, /* Negative Circled 0 */
2894 0x3007, /* Ideographic number zero */
2895 '\0' /* Terminator */
2897 /* Digits in digitRanges for which no representation is available */
2898 static const WCHAR noDigitAvailable[] =
2900 0x0BE6, /* No Tamil 0 */
2901 0x0F29, /* No Tibetan half zero (out of sequence) */
2902 0x1368, /* No Ethiopic 0 */
2903 0x2473, /* No Bracketed 0 */
2904 0x2487, /* No 0 Full stop */
2905 0x24F4, /* No double circled 0 */
2906 0x2775, /* No inverted circled 0 */
2907 0x277F, /* No patterned circled */
2908 0x2789, /* No inverted Patterned circled */
2909 0x3020, /* No Hangzhou 0 */
2910 '\0' /* Terminator */
2912 static const WCHAR foldczone_src[] =
2914 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2915 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2917 static const WCHAR foldczone_dst[] =
2919 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2921 static const WCHAR foldczone_todo_src[] =
2923 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2925 static const WCHAR foldczone_todo_dst[] =
2927 0x3cb,0x1f0,' ','a',0
2929 static const WCHAR foldczone_todo_broken_dst[] =
2931 0x3cb,0x1f0,0xa0,0xaa,0
2933 static const WCHAR ligatures_src[] =
2935 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2936 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2937 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2938 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2939 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2940 0xfb04, 0xfb05, 0xfb06, '\0'
2942 static const WCHAR ligatures_dst[] =
2944 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2945 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2946 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2947 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2948 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2949 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2952 if (!pFoldStringW)
2954 win_skip("FoldStringW is not available\n");
2955 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2958 /* Invalid flag combinations */
2959 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2961 src[0] = dst[0] = '\0';
2962 SetLastError(0);
2963 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2964 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2966 win_skip("FoldStringW is not implemented\n");
2967 return;
2969 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2970 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2973 /* src & dst cannot be the same */
2974 SetLastError(0);
2975 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2976 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2977 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2979 /* src can't be NULL */
2980 SetLastError(0);
2981 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2982 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2983 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2985 /* srclen can't be 0 */
2986 SetLastError(0);
2987 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2988 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2989 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2991 /* dstlen can't be < 0 */
2992 SetLastError(0);
2993 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2994 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2995 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2997 /* Ret includes terminating NUL which is appended if srclen = -1 */
2998 SetLastError(0);
2999 src[0] = 'A';
3000 src[1] = '\0';
3001 dst[0] = '\0';
3002 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3003 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3004 ok(dst[0] == 'A' && dst[1] == '\0',
3005 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3006 'A', '\0', ret, dst[0], dst[1], GetLastError());
3008 /* If size is given, result is not NUL terminated */
3009 SetLastError(0);
3010 src[0] = 'A';
3011 src[1] = 'A';
3012 dst[0] = 'X';
3013 dst[1] = 'X';
3014 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3015 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3016 ok(dst[0] == 'A' && dst[1] == 'X',
3017 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3018 'A','X', ret, dst[0], dst[1], GetLastError());
3020 /* MAP_FOLDDIGITS */
3021 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3023 /* Check everything before this range */
3024 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3026 SetLastError(0);
3027 src[0] = ch;
3028 src[1] = dst[0] = '\0';
3029 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3030 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3032 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3033 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3034 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3035 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3036 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3037 "char %04x should not be a digit\n", ch );
3040 if (digitRanges[j] == 0xffff)
3041 break; /* Finished the whole code point space */
3043 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3045 WCHAR c;
3047 /* Map out of sequence characters */
3048 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3049 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3050 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3051 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3052 else c = ch;
3053 SetLastError(0);
3054 src[0] = c;
3055 src[1] = dst[0] = '\0';
3056 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3057 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3059 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3060 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3061 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3062 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3063 strchrW(noDigitAvailable, c),
3064 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3065 ch, '0' + digitRanges[j] - ch, dst[0]);
3067 prev_ch = ch;
3070 /* MAP_FOLDCZONE */
3071 SetLastError(0);
3072 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3073 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3074 "Got %d, error %d\n", ret, GetLastError());
3075 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3076 "MAP_FOLDCZONE: Expanded incorrectly\n");
3078 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3079 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3080 "Got %d, error %d\n", ret, GetLastError());
3081 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3082 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3083 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3085 /* MAP_EXPAND_LIGATURES */
3086 SetLastError(0);
3087 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3088 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3089 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3090 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3091 "Got %d, error %d\n", ret, GetLastError());
3092 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3093 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3096 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3101 #define LCID_OK(l) \
3102 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3103 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3104 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3105 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3106 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3108 static void test_ConvertDefaultLocale(void)
3110 LCID lcid;
3112 /* Doesn't change lcid, even if non default sublang/sort used */
3113 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3114 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3115 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3116 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3118 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3119 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3120 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3121 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3122 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3124 /* Invariant language is not treated specially */
3125 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3127 /* User/system default languages alone are not mapped */
3128 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3129 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3131 /* Default lcids */
3132 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3133 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3134 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3135 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3136 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3137 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3140 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3141 DWORD dwFlags, LONG_PTR lParam)
3143 if (winetest_debug > 1)
3144 trace("%08x, %s, %s, %08x, %08lx\n",
3145 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3147 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3148 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3150 /* If lParam is one, we are calling with flags defaulted from 0 */
3151 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3152 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3154 return TRUE;
3157 static void test_EnumSystemLanguageGroupsA(void)
3159 BOOL ret;
3161 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3163 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3164 return;
3167 /* No enumeration proc */
3168 SetLastError(0);
3169 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3170 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3172 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3173 return;
3175 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3176 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3178 /* Invalid flags */
3179 SetLastError(0);
3180 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3181 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3183 /* No flags - defaults to LGRPID_INSTALLED */
3184 SetLastError(0xdeadbeef);
3185 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3186 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3188 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3189 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3192 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3194 if (winetest_debug > 1)
3195 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3196 return TRUE;
3199 static void test_EnumSystemLocalesEx(void)
3201 BOOL ret;
3203 if (!pEnumSystemLocalesEx)
3205 win_skip( "EnumSystemLocalesEx not available\n" );
3206 return;
3208 SetLastError( 0xdeadbeef );
3209 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3210 ok( !ret, "should have failed\n" );
3211 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3212 SetLastError( 0xdeadbeef );
3213 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3214 ok( ret, "failed err %u\n", GetLastError() );
3217 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3218 LONG_PTR lParam)
3220 if (winetest_debug > 1)
3221 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3223 /* invalid locale enumerated on some platforms */
3224 if (lcid == 0)
3225 return TRUE;
3227 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3228 "Enumerated grp %d not valid\n", lgrpid);
3229 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3230 "Enumerated grp locale %04x not valid\n", lcid);
3231 return TRUE;
3234 static void test_EnumLanguageGroupLocalesA(void)
3236 BOOL ret;
3238 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3240 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3241 return;
3244 /* No enumeration proc */
3245 SetLastError(0);
3246 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3247 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3249 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3250 return;
3252 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3253 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3255 /* lgrpid too small */
3256 SetLastError(0);
3257 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3258 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3259 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3261 /* lgrpid too big */
3262 SetLastError(0);
3263 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3264 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3265 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3267 /* dwFlags is reserved */
3268 SetLastError(0);
3269 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3270 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3271 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3273 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3276 static void test_SetLocaleInfoA(void)
3278 BOOL bRet;
3279 LCID lcid = GetUserDefaultLCID();
3281 /* Null data */
3282 SetLastError(0);
3283 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3284 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3285 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3287 /* IDATE */
3288 SetLastError(0);
3289 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3290 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3291 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3293 /* ILDATE */
3294 SetLastError(0);
3295 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3296 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3297 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3300 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3302 if (winetest_debug > 1)
3303 trace("%s %08lx\n", value, lParam);
3304 return(TRUE);
3307 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3309 ok(!enumCount, "callback called again unexpected\n");
3310 enumCount++;
3311 return(FALSE);
3314 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3316 ok(0,"callback called unexpected\n");
3317 return(FALSE);
3320 static void test_EnumUILanguageA(void)
3322 BOOL ret;
3323 if (!pEnumUILanguagesA) {
3324 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3325 return;
3328 SetLastError(ERROR_SUCCESS);
3329 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3330 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3332 win_skip("EnumUILanguagesA is not implemented\n");
3333 return;
3335 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3337 enumCount = 0;
3338 SetLastError(ERROR_SUCCESS);
3339 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3340 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3342 SetLastError(ERROR_SUCCESS);
3343 ret = pEnumUILanguagesA(NULL, 0, 0);
3344 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3345 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3346 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3348 SetLastError(ERROR_SUCCESS);
3349 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3350 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3351 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3353 SetLastError(ERROR_SUCCESS);
3354 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3355 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3356 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3357 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3360 static char date_fmt_buf[1024];
3362 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3364 lstrcatA(date_fmt_buf, fmt);
3365 lstrcatA(date_fmt_buf, "\n");
3366 return TRUE;
3369 static void test_EnumDateFormatsA(void)
3371 char *p, buf[256];
3372 BOOL ret;
3373 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3375 date_fmt_buf[0] = 0;
3376 SetLastError(0xdeadbeef);
3377 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3378 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3380 win_skip("0 for dwFlags is not supported\n");
3382 else
3384 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3385 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3386 /* test the 1st enumerated format */
3387 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3388 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3389 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3390 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3393 date_fmt_buf[0] = 0;
3394 SetLastError(0xdeadbeef);
3395 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3396 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3398 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3400 else
3402 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3403 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3404 /* test the 1st enumerated format */
3405 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3406 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3407 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3408 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3411 date_fmt_buf[0] = 0;
3412 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3413 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3414 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3415 /* test the 1st enumerated format */
3416 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3417 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3418 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3419 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3421 date_fmt_buf[0] = 0;
3422 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3423 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3424 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3425 /* test the 1st enumerated format */
3426 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3427 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3428 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3429 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3431 date_fmt_buf[0] = 0;
3432 SetLastError(0xdeadbeef);
3433 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3434 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3436 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3437 return;
3439 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3440 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3441 /* test the 1st enumerated format */
3442 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3443 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3444 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3445 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3446 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3449 static void test_EnumTimeFormatsA(void)
3451 char *p, buf[256];
3452 BOOL ret;
3453 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3455 date_fmt_buf[0] = 0;
3456 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3457 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3458 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3459 /* test the 1st enumerated format */
3460 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3461 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3462 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3463 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3465 date_fmt_buf[0] = 0;
3466 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3467 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3468 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3469 /* test the 1st enumerated format */
3470 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3471 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3472 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3473 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3476 static void test_GetCPInfo(void)
3478 BOOL ret;
3479 CPINFO cpinfo;
3481 SetLastError(0xdeadbeef);
3482 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3483 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3484 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3485 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3487 SetLastError(0xdeadbeef);
3488 ret = GetCPInfo(CP_UTF7, &cpinfo);
3489 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3491 win_skip("Codepage CP_UTF7 is not installed/available\n");
3493 else
3495 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3496 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3497 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3498 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3499 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3500 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3503 SetLastError(0xdeadbeef);
3504 ret = GetCPInfo(CP_UTF8, &cpinfo);
3505 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3507 win_skip("Codepage CP_UTF8 is not installed/available\n");
3509 else
3511 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3512 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3513 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3514 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3515 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3516 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3517 "expected 4, got %u\n", cpinfo.MaxCharSize);
3522 * The CT_TYPE1 has varied over windows version.
3523 * The current target for correct behavior is windows 7.
3524 * There was a big shift between windows 2000 (first introduced) and windows Xp
3525 * Most of the old values below are from windows 2000.
3526 * A smaller subset of changes happened between windows Xp and Window vista/7
3528 static void test_GetStringTypeW(void)
3530 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3531 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3532 C1_SPACE | C1_BLANK | C1_DEFINED,
3533 C1_SPACE | C1_BLANK | C1_DEFINED,
3534 C1_SPACE | C1_BLANK | C1_DEFINED,
3535 C1_CNTRL | C1_BLANK | C1_DEFINED};
3536 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3537 C1_SPACE | C1_BLANK,
3538 C1_SPACE | C1_BLANK,
3539 C1_SPACE | C1_BLANK,
3540 C1_SPACE | C1_BLANK};
3542 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3544 /* Lu, Ll, Lt */
3545 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3546 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3547 C1_LOWER | C1_ALPHA,
3548 C1_UPPER | C1_LOWER | C1_ALPHA,
3549 C1_ALPHA};
3551 /* Sk, Sk, Mn, So, Me */
3552 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3553 /* Sc, Sm, No,*/
3554 0xffe0, 0xffe9, 0x2153};
3556 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3557 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3558 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3559 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3560 C1_ALPHA | C1_DEFINED,
3561 C1_CNTRL | C1_DEFINED,
3562 C1_PUNCT | C1_DEFINED,
3563 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3564 C1_ALPHA | C1_LOWER | C1_DEFINED,
3565 C1_ALPHA | C1_DEFINED };
3566 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3567 C1_ALPHA | C1_DEFINED,
3568 C1_CNTRL | C1_DEFINED,
3569 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3570 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3571 C1_ALPHA | C1_DEFINED,
3572 C1_DEFINED
3574 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3575 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3577 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3578 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3579 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3580 static const WCHAR lower_special[] = {0x2071, 0x207f};
3581 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3582 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3583 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3584 0xfff9, 0xfffa, 0xfffb};
3585 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3587 WORD types[20];
3588 BOOL ret;
3589 WCHAR ch;
3590 int i;
3592 /* NULL src */
3593 SetLastError(0xdeadbeef);
3594 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3595 ok(!ret, "got %d\n", ret);
3596 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3598 SetLastError(0xdeadbeef);
3599 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3600 ok(!ret, "got %d\n", ret);
3601 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3603 SetLastError(0xdeadbeef);
3604 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3605 ok(!ret, "got %d\n", ret);
3606 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3608 memset(types,0,sizeof(types));
3609 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3610 for (i = 0; i < 5; i++)
3611 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]);
3613 memset(types,0,sizeof(types));
3614 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3615 for (i = 0; i < 3; i++)
3616 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]));
3617 memset(types,0,sizeof(types));
3618 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3619 for (i = 0; i < 5; i++)
3620 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3622 memset(types,0,sizeof(types));
3623 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3624 for (i = 0; i < 8; i++)
3625 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);
3627 memset(types,0,sizeof(types));
3628 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3629 for (i = 0; i < 7; i++)
3630 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]);
3632 memset(types,0,sizeof(types));
3633 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3634 for (i = 0; i < 7; i++)
3635 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));
3638 memset(types,0,sizeof(types));
3639 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3640 for (i = 0; i < 12; i++)
3641 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);
3643 memset(types,0,sizeof(types));
3644 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3645 for (i = 0; i < 3; i++)
3646 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);
3648 memset(types,0,sizeof(types));
3649 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3650 for (i = 0; i < 2; i++)
3651 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);
3653 memset(types,0,sizeof(types));
3654 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3655 for (i = 0; i < 20; i++)
3656 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);
3658 memset(types,0,sizeof(types));
3659 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3660 for (i = 0; i < 3; i++)
3661 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 );
3663 /* surrogate pairs */
3664 ch = 0xd800;
3665 memset(types, 0, sizeof(types));
3666 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3667 if (types[0] == C3_NOTAPPLICABLE)
3668 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
3669 else {
3670 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
3672 ch = 0xdc00;
3673 memset(types, 0, sizeof(types));
3674 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3675 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
3679 static void test_IdnToNameprepUnicode(void)
3681 struct {
3682 DWORD in_len;
3683 const WCHAR in[64];
3684 DWORD ret;
3685 DWORD broken_ret;
3686 const WCHAR out[64];
3687 DWORD flags;
3688 DWORD err;
3689 DWORD todo;
3690 } test_data[] = {
3692 5, {'t','e','s','t',0},
3693 5, 5, {'t','e','s','t',0},
3694 0, 0xdeadbeef
3697 3, {'a',0xe111,'b'},
3698 0, 0, {0},
3699 0, ERROR_INVALID_NAME
3702 4, {'t',0,'e',0},
3703 0, 0, {0},
3704 0, ERROR_INVALID_NAME
3707 1, {'T',0},
3708 1, 1, {'T',0},
3709 0, 0xdeadbeef
3712 1, {0},
3713 0, 0, {0},
3714 0, ERROR_INVALID_NAME
3717 6, {' ','-','/','[',']',0},
3718 6, 6, {' ','-','/','[',']',0},
3719 0, 0xdeadbeef
3722 3, {'a','-','a'},
3723 3, 3, {'a','-','a'},
3724 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3727 3, {'a','a','-'},
3728 0, 0, {0},
3729 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3731 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3732 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3733 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3734 0, 0xdeadbeef, TRUE
3737 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3738 2, 0, {'t',0},
3739 0, 0xdeadbeef
3741 { /* Another example of incorrectly working FoldString (composition) */
3742 2, {0x3b0, 0},
3743 2, 2, {0x3b0, 0},
3744 0, 0xdeadbeef, TRUE
3747 2, {0x221, 0},
3748 0, 2, {0},
3749 0, ERROR_NO_UNICODE_TRANSLATION
3752 2, {0x221, 0},
3753 2, 2, {0x221, 0},
3754 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3757 5, {'a','.','.','a',0},
3758 0, 0, {0},
3759 0, ERROR_INVALID_NAME
3762 3, {'a','.',0},
3763 3, 3, {'a','.',0},
3764 0, 0xdeadbeef
3768 WCHAR buf[1024];
3769 DWORD i, ret, err;
3771 if (!pIdnToNameprepUnicode)
3773 win_skip("IdnToNameprepUnicode is not available\n");
3774 return;
3777 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3778 test_data[0].in_len, NULL, 0);
3779 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3781 SetLastError(0xdeadbeef);
3782 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3783 test_data[1].in_len, NULL, 0);
3784 err = GetLastError();
3785 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3786 ok(err == test_data[1].err, "err = %d\n", err);
3788 SetLastError(0xdeadbeef);
3789 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3790 buf, sizeof(buf)/sizeof(WCHAR));
3791 err = GetLastError();
3792 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3793 ok(err == 0xdeadbeef, "err = %d\n", err);
3795 SetLastError(0xdeadbeef);
3796 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3797 buf, sizeof(buf)/sizeof(WCHAR));
3798 err = GetLastError();
3799 ok(ret == 0, "ret = %d\n", ret);
3800 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3802 SetLastError(0xdeadbeef);
3803 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3804 buf, sizeof(buf)/sizeof(WCHAR));
3805 err = GetLastError();
3806 ok(ret == 0, "ret = %d\n", ret);
3807 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3809 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3810 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3811 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3813 SetLastError(0xdeadbeef);
3814 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3815 err = GetLastError();
3816 ok(ret == 0, "ret = %d\n", ret);
3817 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3819 SetLastError(0xdeadbeef);
3820 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3821 err = GetLastError();
3822 ok(ret == 0, "ret = %d\n", ret);
3823 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
3824 "err = %d\n", err);
3826 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3828 SetLastError(0xdeadbeef);
3829 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3830 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3831 err = GetLastError();
3833 if (!test_data[i].todo)
3835 ok(ret == test_data[i].ret ||
3836 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3838 else
3840 todo_wine ok(ret == test_data[i].ret ||
3841 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3843 if(ret != test_data[i].ret)
3844 continue;
3846 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3847 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3848 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3852 static void test_IdnToAscii(void)
3854 struct {
3855 DWORD in_len;
3856 const WCHAR in[64];
3857 DWORD ret;
3858 const WCHAR out[64];
3859 DWORD flags;
3860 DWORD err;
3861 } test_data[] = {
3863 5, {'T','e','s','t',0},
3864 5, {'T','e','s','t',0},
3865 0, 0xdeadbeef
3868 5, {'T','e',0x017c,'s','t',0},
3869 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3870 0, 0xdeadbeef
3873 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3874 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3875 0, 0xdeadbeef
3878 3, {0x0105,'.',0},
3879 9, {'x','n','-','-','2','d','a','.',0},
3880 0, 0xdeadbeef
3883 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3884 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3885 0, 0xdeadbeef
3888 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3889 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3890 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3891 0, 0xdeadbeef
3894 2, {0x221,0},
3895 8, {'x','n','-','-','6','l','a',0},
3896 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3900 WCHAR buf[1024];
3901 DWORD i, ret, err;
3903 if (!pIdnToAscii)
3905 win_skip("IdnToAscii is not available\n");
3906 return;
3909 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3911 SetLastError(0xdeadbeef);
3912 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3913 test_data[i].in_len, buf, sizeof(buf));
3914 err = GetLastError();
3915 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3916 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3917 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3918 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3922 static void test_IdnToUnicode(void)
3924 struct {
3925 DWORD in_len;
3926 const WCHAR in[64];
3927 DWORD ret;
3928 const WCHAR out[64];
3929 DWORD flags;
3930 DWORD err;
3931 } test_data[] = {
3933 5, {'T','e','s','.',0},
3934 5, {'T','e','s','.',0},
3935 0, 0xdeadbeef
3938 2, {0x105,0},
3939 0, {0},
3940 0, ERROR_INVALID_NAME
3943 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3944 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3945 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3946 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3947 0x05d1,0x05e8,0x05d9,0x05ea,0},
3948 0, 0xdeadbeef
3951 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3952 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3953 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3954 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3955 0, 0xdeadbeef
3958 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3959 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3960 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3961 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3962 0, {0},
3963 0, ERROR_INVALID_NAME
3966 8, {'x','n','-','-','6','l','a',0},
3967 2, {0x221,0},
3968 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3972 WCHAR buf[1024];
3973 DWORD i, ret, err;
3975 if (!pIdnToUnicode)
3977 win_skip("IdnToUnicode is not available\n");
3978 return;
3981 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3983 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3984 test_data[i].in_len, NULL, 0);
3985 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3987 SetLastError(0xdeadbeef);
3988 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3989 test_data[i].in_len, buf, sizeof(buf));
3990 err = GetLastError();
3991 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3992 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3993 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3994 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3998 static void test_GetLocaleInfoEx(void)
4000 static const WCHAR enW[] = {'e','n',0};
4001 WCHAR bufferW[80];
4002 INT ret;
4004 if (!pGetLocaleInfoEx)
4006 win_skip("GetLocaleInfoEx not supported\n");
4007 return;
4010 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4011 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4012 if (ret)
4014 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4015 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4016 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4017 static const WCHAR usaW[] = {'U','S','A',0};
4018 static const WCHAR enuW[] = {'E','N','U',0};
4019 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4020 DWORD val;
4022 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4023 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4025 SetLastError(0xdeadbeef);
4026 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4027 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4029 SetLastError(0xdeadbeef);
4030 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4031 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4033 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4034 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4035 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4037 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4038 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4039 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4041 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4042 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4043 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4045 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4046 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4047 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4048 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4050 skip("Non-English locale\n");
4052 else
4053 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4055 bufferW[0] = 0;
4056 SetLastError(0xdeadbeef);
4057 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4058 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4060 while (*ptr->name)
4062 val = 0;
4063 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4064 if (ptr->todo)
4065 todo_wine
4066 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4067 else
4068 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4069 bufferW[0] = 0;
4070 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4071 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4072 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4073 ptr++;
4078 static void test_IsValidLocaleName(void)
4080 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4081 static const WCHAR zzW[] = {'z','z',0};
4082 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4083 BOOL ret;
4085 if (!pIsValidLocaleName)
4087 win_skip("IsValidLocaleName not supported\n");
4088 return;
4091 ret = pIsValidLocaleName(enusW);
4092 ok(ret, "IsValidLocaleName failed\n");
4093 ret = pIsValidLocaleName(zzW);
4094 ok(!ret, "IsValidLocaleName should have failed\n");
4095 ret = pIsValidLocaleName(zzzzW);
4096 ok(!ret, "IsValidLocaleName should have failed\n");
4097 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4098 ok(ret, "IsValidLocaleName failed\n");
4101 static void test_CompareStringOrdinal(void)
4103 INT ret;
4104 WCHAR test1[] = { 't','e','s','t',0 };
4105 WCHAR test2[] = { 'T','e','S','t',0 };
4106 WCHAR test3[] = { 't','e','s','t','3',0 };
4107 WCHAR null1[] = { 'a',0,'a',0 };
4108 WCHAR null2[] = { 'a',0,'b',0 };
4109 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4110 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4111 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4112 WCHAR coop2[] = { 'c','o','o','p',0 };
4113 WCHAR nonascii1[] = { 0x0102,0 };
4114 WCHAR nonascii2[] = { 0x0201,0 };
4116 if (!pCompareStringOrdinal)
4118 win_skip("CompareStringOrdinal not supported\n");
4119 return;
4122 /* Check errors */
4123 SetLastError(0xdeadbeef);
4124 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4125 ok(!ret, "Got %u, expected 0\n", ret);
4126 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4127 SetLastError(0xdeadbeef);
4128 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4129 ok(!ret, "Got %u, expected 0\n", ret);
4130 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4131 SetLastError(0xdeadbeef);
4132 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4133 ok(!ret, "Got %u, expected 0\n", ret);
4134 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4136 /* Check case */
4137 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4138 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4139 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4140 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4141 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4142 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4143 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4144 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4146 /* Check different sizes */
4147 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4148 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4149 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4150 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4152 /* Check null character */
4153 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4154 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4155 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4156 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4157 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4158 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4159 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4160 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4162 /* Check ordinal behaviour */
4163 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4164 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4165 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4166 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4167 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4168 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4169 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4170 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4173 static void test_GetGeoInfo(void)
4175 char buffA[20];
4176 INT ret;
4178 if (!pGetGeoInfoA)
4180 win_skip("GetGeoInfo is not available.\n");
4181 return;
4184 /* unassigned id */
4185 SetLastError(0xdeadbeef);
4186 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4187 ok(ret == 0, "got %d\n", ret);
4188 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4190 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4191 ok(ret == 3, "got %d\n", ret);
4193 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4194 ok(ret == 4, "got %d\n", ret);
4196 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4197 ok(ret == 3, "got %d\n", ret);
4198 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4200 /* buffer pointer not NULL, length is 0 - return required length */
4201 buffA[0] = 'a';
4202 SetLastError(0xdeadbeef);
4203 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4204 ok(ret == 3, "got %d\n", ret);
4205 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4207 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4208 ok(ret == 4, "got %d\n", ret);
4209 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4211 /* shorter buffer */
4212 SetLastError(0xdeadbeef);
4213 buffA[1] = buffA[2] = 0;
4214 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4215 ok(ret == 0, "got %d\n", ret);
4216 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4217 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4219 /* GEO_NATION returns GEOID in a string form */
4220 buffA[0] = 0;
4221 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4222 ok(ret == 4, "got %d\n", ret);
4223 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4225 /* GEO_PARENT */
4226 buffA[0] = 0;
4227 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4228 if (ret == 0)
4229 win_skip("GEO_PARENT not supported.\n");
4230 else
4232 ok(ret == 6, "got %d\n", ret);
4233 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4236 buffA[0] = 0;
4237 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4238 if (ret == 0)
4239 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4240 else
4242 ok(ret == 4, "got %d\n", ret);
4243 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4246 /* try invalid type value */
4247 SetLastError(0xdeadbeef);
4248 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4249 ok(ret == 0, "got %d\n", ret);
4250 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4253 static int geoidenum_count;
4254 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4256 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4257 ok(ret == 3, "got %d for %d\n", ret, geoid);
4258 /* valid geoid starts at 2 */
4259 ok(geoid >= 2, "got geoid %d\n", geoid);
4261 return geoidenum_count++ < 5;
4264 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4266 geoidenum_count++;
4267 return TRUE;
4270 static void test_EnumSystemGeoID(void)
4272 BOOL ret;
4274 if (!pEnumSystemGeoID)
4276 win_skip("EnumSystemGeoID is not available.\n");
4277 return;
4280 SetLastError(0xdeadbeef);
4281 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4282 ok(!ret, "got %d\n", ret);
4283 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4285 SetLastError(0xdeadbeef);
4286 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4287 ok(!ret, "got %d\n", ret);
4288 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4290 SetLastError(0xdeadbeef);
4291 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4292 ok(!ret, "got %d\n", ret);
4293 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4295 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4296 ok(ret, "got %d\n", ret);
4298 /* only the first level is enumerated, not the whole hierarchy */
4299 geoidenum_count = 0;
4300 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4301 if (ret == 0)
4302 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4303 else
4304 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4306 geoidenum_count = 0;
4307 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4308 if (ret == 0)
4309 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4310 else
4312 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4314 geoidenum_count = 0;
4315 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4316 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4320 START_TEST(locale)
4322 InitFunctionPointers();
4324 test_EnumTimeFormatsA();
4325 test_EnumDateFormatsA();
4326 test_GetLocaleInfoA();
4327 test_GetLocaleInfoW();
4328 test_GetLocaleInfoEx();
4329 test_GetTimeFormatA();
4330 test_GetTimeFormatEx();
4331 test_GetDateFormatA();
4332 test_GetDateFormatEx();
4333 test_GetDateFormatW();
4334 test_GetCurrencyFormatA(); /* Also tests the W version */
4335 test_GetNumberFormatA(); /* Also tests the W version */
4336 test_CompareStringA();
4337 test_CompareStringEx();
4338 test_LCMapStringA();
4339 test_LCMapStringW();
4340 test_LCMapStringEx();
4341 test_LocaleNameToLCID();
4342 test_FoldStringA();
4343 test_FoldStringW();
4344 test_ConvertDefaultLocale();
4345 test_EnumSystemLanguageGroupsA();
4346 test_EnumSystemLocalesEx();
4347 test_EnumLanguageGroupLocalesA();
4348 test_SetLocaleInfoA();
4349 test_EnumUILanguageA();
4350 test_GetCPInfo();
4351 test_GetStringTypeW();
4352 test_IdnToNameprepUnicode();
4353 test_IdnToAscii();
4354 test_IdnToUnicode();
4355 test_IsValidLocaleName();
4356 test_CompareStringOrdinal();
4357 test_GetGeoInfo();
4358 test_EnumSystemGeoID();
4359 /* this requires collation table patch to make it MS compatible */
4360 if (0) test_sorting();