kernel32/tests: Add tests for GetSystemPreferredUILanguages.
[wine.git] / dlls / kernel32 / tests / locale.c
blobb760e9a2ce7c7175d8457527e7edcdde8495eafe
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);
100 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static void InitFunctionPointers(void)
104 hKernel32 = GetModuleHandleA("kernel32");
106 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
107 X(GetTimeFormatEx);
108 X(GetDateFormatEx);
109 X(EnumSystemLanguageGroupsA);
110 X(EnumLanguageGroupLocalesA);
111 X(LocaleNameToLCID);
112 X(LCIDToLocaleName);
113 X(LCMapStringEx);
114 X(FoldStringA);
115 X(FoldStringW);
116 X(IsValidLanguageGroup);
117 X(EnumUILanguagesA);
118 X(EnumSystemLocalesEx);
119 X(IdnToNameprepUnicode);
120 X(IdnToAscii);
121 X(IdnToUnicode);
122 X(GetLocaleInfoEx);
123 X(IsValidLocaleName);
124 X(CompareStringOrdinal);
125 X(CompareStringEx);
126 X(GetGeoInfoA);
127 X(GetGeoInfoW);
128 X(EnumSystemGeoID);
129 X(GetSystemPreferredUILanguages);
130 #undef X
133 #define eq(received, expected, label, type) \
134 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
135 (label), (received), (expected))
137 #define BUFFER_SIZE 128
138 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
140 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
141 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
142 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
143 "Expected '%s', got '%s'\n", Expected, buffer)
145 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
146 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
147 SetLastError(0xdeadbeef); buffer[0] = '\0'
148 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
149 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
151 #define NUO LOCALE_NOUSEROVERRIDE
153 static void test_GetLocaleInfoA(void)
155 int ret;
156 int len;
157 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
158 char buffer[BUFFER_SIZE];
159 char expected[BUFFER_SIZE];
160 DWORD val;
162 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
164 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
165 ok(ret, "got %d\n", ret);
166 ok(val == lcid, "got 0x%08x\n", val);
168 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
169 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
170 assumes SUBLANG_NEUTRAL for zh */
171 memset(expected, 0, COUNTOF(expected));
172 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
173 SetLastError(0xdeadbeef);
174 memset(buffer, 0, COUNTOF(buffer));
175 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
176 ok((ret == len) && !lstrcmpA(buffer, expected),
177 "got %d with '%s' (expected %d with '%s')\n",
178 ret, buffer, len, expected);
180 memset(expected, 0, COUNTOF(expected));
181 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
182 if (len) {
183 SetLastError(0xdeadbeef);
184 memset(buffer, 0, COUNTOF(buffer));
185 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
186 ok((ret == len) && !lstrcmpA(buffer, expected),
187 "got %d with '%s' (expected %d with '%s')\n",
188 ret, buffer, len, expected);
190 else
191 win_skip("LANG_ARABIC not installed\n");
193 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
194 memset(expected, 0, COUNTOF(expected));
195 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
196 SetLastError(0xdeadbeef);
197 memset(buffer, 0, COUNTOF(buffer));
198 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
199 ok((ret == len) && !lstrcmpA(buffer, expected),
200 "got %d with '%s' (expected %d with '%s')\n",
201 ret, buffer, len, expected);
204 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
205 * partially fill the buffer even if it is too short. See bug 637.
207 SetLastError(0xdeadbeef);
208 memset(buffer, 0, COUNTOF(buffer));
209 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
210 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
212 SetLastError(0xdeadbeef);
213 memset(buffer, 0, COUNTOF(buffer));
214 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
215 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
216 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
217 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
219 SetLastError(0xdeadbeef);
220 memset(buffer, 0, COUNTOF(buffer));
221 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
222 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
223 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
226 struct neutralsublang_name2_t {
227 WCHAR name[3];
228 WCHAR sname[15];
229 LCID lcid;
230 LCID lcid_broken;
231 WCHAR sname_broken[15];
232 int todo;
235 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
236 { {'a','r',0}, {'a','r','-','S','A',0},
237 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
238 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
239 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
240 { {'d','e',0}, {'d','e','-','D','E',0},
241 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
242 { {'e','n',0}, {'e','n','-','U','S',0},
243 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
244 { {'e','s',0}, {'e','s','-','E','S',0},
245 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
246 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
247 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
248 { {'g','a',0}, {'g','a','-','I','E',0},
249 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
250 { {'i','t',0}, {'i','t','-','I','T',0},
251 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
252 { {'m','s',0}, {'m','s','-','M','Y',0},
253 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
254 { {'n','l',0}, {'n','l','-','N','L',0},
255 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
256 { {'p','t',0}, {'p','t','-','B','R',0},
257 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
258 { {'s','r',0}, {'h','r','-','H','R',0},
259 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
260 { {'s','v',0}, {'s','v','-','S','E',0},
261 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
262 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
263 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
264 { {'z','h',0}, {'z','h','-','C','N',0},
265 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
266 { {0} }
269 static void test_GetLocaleInfoW(void)
271 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
272 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
273 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
274 WCHAR bufferW[80], buffer2W[80];
275 CHAR bufferA[80];
276 DWORD val;
277 DWORD ret;
278 INT i;
280 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
281 if (!ret) {
282 win_skip("GetLocaleInfoW() isn't implemented\n");
283 return;
286 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
287 ok(ret, "got %d\n", ret);
288 ok(val == lcid_en, "got 0x%08x\n", val);
290 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
291 if (ret)
293 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
294 'S','t','a','t','e','s',')',0};
295 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
296 static const WCHAR enW[] = {'e','n','-','U','S',0};
297 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
299 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
301 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
302 ok(ret, "got %d\n", ret);
303 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
304 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
306 skip("Non-English locale\n");
308 else
309 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
311 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
312 ok(ret, "got %d\n", ret);
313 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
314 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
316 skip("Non-English locale\n");
318 else
319 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
321 while (*ptr->name)
323 LANGID langid;
324 LCID lcid;
326 /* make neutral lcid */
327 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
328 lcid = MAKELCID(langid, SORT_DEFAULT);
330 val = 0;
331 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
332 if (ptr->todo & 0x1)
334 todo_wine
335 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
336 wine_dbgstr_w(ptr->name), val, ptr->lcid);
338 else
339 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
340 wine_dbgstr_w(ptr->name), val, ptr->lcid);
342 /* now check LOCALE_SNAME */
343 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
344 if (ptr->todo & 0x2)
345 todo_wine
346 ok(!lstrcmpW(bufferW, ptr->sname) ||
347 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
348 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
349 else
350 ok(!lstrcmpW(bufferW, ptr->sname) ||
351 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
352 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
353 ptr++;
356 else
357 win_skip("English neutral locale not supported\n");
359 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
360 if (!ret) {
361 win_skip("LANG_RUSSIAN locale data unavailable\n");
362 return;
364 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
365 bufferW, COUNTOF(bufferW));
366 if (!ret) {
367 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
368 return;
371 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
372 bufferA[0] = 'a';
373 SetLastError(0xdeadbeef);
374 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
375 bufferA, COUNTOF(bufferA));
376 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
377 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
378 ok(GetLastError() == ERROR_INVALID_FLAGS,
379 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
381 bufferW[0] = 'a';
382 SetLastError(0xdeadbeef);
383 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
384 bufferW, COUNTOF(bufferW));
385 ok(ret == 0,
386 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
387 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
388 ok(GetLastError() == ERROR_INVALID_FLAGS,
389 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
391 /* yes, test empty 13 month entry too */
392 for (i = 0; i < 12; i++) {
393 bufferW[0] = 0;
394 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
395 bufferW, COUNTOF(bufferW));
396 ok(ret, "Expected non zero result\n");
397 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
398 ret, lstrlenW(bufferW));
399 buffer2W[0] = 0;
400 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
401 buffer2W, COUNTOF(buffer2W));
402 ok(ret, "Expected non zero result\n");
403 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
404 ret, lstrlenW(buffer2W));
406 ok(lstrcmpW(bufferW, buffer2W) != 0,
407 "Expected genitive name to differ, got the same for month %d\n", i+1);
409 /* for locale without genitive names nominative returned in both cases */
410 bufferW[0] = 0;
411 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
412 bufferW, COUNTOF(bufferW));
413 ok(ret, "Expected non zero result\n");
414 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
415 ret, lstrlenW(bufferW));
416 buffer2W[0] = 0;
417 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
418 buffer2W, COUNTOF(buffer2W));
419 ok(ret, "Expected non zero result\n");
420 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
421 ret, lstrlenW(buffer2W));
423 ok(lstrcmpW(bufferW, buffer2W) == 0,
424 "Expected same names, got different for month %d\n", i+1);
428 static void test_GetTimeFormatA(void)
430 int ret;
431 SYSTEMTIME curtime;
432 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
433 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
435 memset(&curtime, 2, sizeof(SYSTEMTIME));
436 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
437 SetLastError(0xdeadbeef);
438 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
442 curtime.wHour = 8;
443 curtime.wMinute = 56;
444 curtime.wSecond = 13;
445 curtime.wMilliseconds = 22;
446 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
447 SetLastError(0xdeadbeef);
448 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
450 EXPECT_LENA; EXPECT_EQA;
452 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
453 SetLastError(0xdeadbeef);
454 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
455 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
456 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
458 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
459 SetLastError(0xdeadbeef);
460 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
461 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
462 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
464 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
465 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
466 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
467 EXPECT_LENA;
469 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
470 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
472 EXPECT_LENA; EXPECT_EQA;
474 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
475 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
476 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
477 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
478 "Expected '', got '%s'\n", buffer );
480 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
481 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 EXPECT_LENA; EXPECT_EQA;
485 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
486 strcpy(Expected, "8:56 AM");
487 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
488 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
489 EXPECT_LENA; EXPECT_EQA;
491 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
492 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
493 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
494 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
495 "Expected '8.@:56AM', got '%s'\n", buffer );
497 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
498 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
499 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
500 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
501 "Expected '', got '%s'\n", buffer );
503 STRINGSA("t/tt", "A/AM"); /* AM time marker */
504 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
505 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
506 EXPECT_LENA; EXPECT_EQA;
508 curtime.wHour = 13;
509 STRINGSA("t/tt", "P/PM"); /* PM time marker */
510 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
512 EXPECT_LENA; EXPECT_EQA;
514 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
515 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
516 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
517 EXPECT_LENA; EXPECT_EQA;
519 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
520 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
521 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
522 EXPECT_LENA; EXPECT_EQA;
524 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
525 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
527 EXPECT_LENA; EXPECT_EQA;
529 curtime.wHour = 14; /* change this to 14 or 2pm */
530 curtime.wMinute = 5;
531 curtime.wSecond = 3;
532 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 */
533 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
534 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
535 EXPECT_LENA; EXPECT_EQA;
537 curtime.wHour = 0;
538 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
539 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
540 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
541 EXPECT_LENA; EXPECT_EQA;
543 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
544 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
545 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
546 EXPECT_LENA; EXPECT_EQA;
548 /* try to convert formatting strings with more than two letters
549 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
550 * NOTE: We expect any letter for which there is an upper case value
551 * we should see a replacement. For letters that DO NOT have
552 * upper case values we should see NO REPLACEMENT.
554 curtime.wHour = 8;
555 curtime.wMinute = 56;
556 curtime.wSecond = 13;
557 curtime.wMilliseconds = 22;
558 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
559 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
560 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 EXPECT_LENA; EXPECT_EQA;
564 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
565 strcpy(buffer, "text");
566 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
567 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
568 EXPECT_EQA;
570 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
571 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
572 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
573 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
574 EXPECT_LENA; EXPECT_EQA;
576 STRINGSA("'''", "'"); /* invalid quoted string */
577 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
579 EXPECT_LENA; EXPECT_EQA;
581 /* test that msdn suggested single quotation usage works as expected */
582 STRINGSA("''''", "'"); /* single quote mark */
583 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
585 EXPECT_LENA; EXPECT_EQA;
587 STRINGSA("''HHHHHH", "08"); /* Normal use */
588 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
589 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
590 EXPECT_LENA; EXPECT_EQA;
592 /* and test for normal use of the single quotation mark */
593 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
594 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
595 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
596 EXPECT_LENA; EXPECT_EQA;
598 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
599 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
600 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
601 EXPECT_LENA; EXPECT_EQA;
603 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
604 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
605 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
606 EXPECT_LENA; EXPECT_EQA;
608 curtime.wHour = 25;
609 STRINGSA("'123'tt", ""); /* Invalid time */
610 SetLastError(0xdeadbeef);
611 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
612 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
613 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
615 curtime.wHour = 12;
616 curtime.wMonth = 60; /* Invalid */
617 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
618 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
619 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
620 EXPECT_LENA; EXPECT_EQA;
623 static void test_GetTimeFormatEx(void)
625 int ret;
626 SYSTEMTIME curtime;
627 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
629 if (!pGetTimeFormatEx)
631 win_skip("GetTimeFormatEx not supported\n");
632 return;
635 memset(&curtime, 2, sizeof(SYSTEMTIME));
636 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
637 SetLastError(0xdeadbeef);
638 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
639 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
640 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
642 curtime.wHour = 8;
643 curtime.wMinute = 56;
644 curtime.wSecond = 13;
645 curtime.wMilliseconds = 22;
646 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
647 SetLastError(0xdeadbeef);
648 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
649 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
650 EXPECT_LENW; EXPECT_EQW;
652 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
653 SetLastError(0xdeadbeef);
654 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
655 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
656 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
658 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
659 SetLastError(0xdeadbeef);
660 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
661 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
662 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
664 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
665 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
666 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
667 EXPECT_LENW;
669 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
670 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
672 EXPECT_LENW; EXPECT_EQW;
674 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
675 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
676 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
677 EXPECT_LENW; EXPECT_EQW;
679 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
680 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
682 EXPECT_LENW; EXPECT_EQW;
684 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
685 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
686 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
687 EXPECT_LENW; EXPECT_EQW;
689 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
690 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
691 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
692 EXPECT_LENW; EXPECT_EQW;
694 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
695 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
696 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
697 EXPECT_LENW; EXPECT_EQW;
699 STRINGSW("t/tt", "A/AM"); /* AM time marker */
700 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 EXPECT_LENW; EXPECT_EQW;
704 curtime.wHour = 13;
705 STRINGSW("t/tt", "P/PM"); /* PM time marker */
706 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 EXPECT_LENW; EXPECT_EQW;
710 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
711 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 EXPECT_LENW; EXPECT_EQW;
715 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
716 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
718 EXPECT_LENW; EXPECT_EQW;
720 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
721 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
722 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
723 EXPECT_LENW; EXPECT_EQW;
725 curtime.wHour = 14; /* change this to 14 or 2pm */
726 curtime.wMinute = 5;
727 curtime.wSecond = 3;
728 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 */
729 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
730 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
731 EXPECT_LENW; EXPECT_EQW;
733 curtime.wHour = 0;
734 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
735 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
736 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
737 EXPECT_LENW; EXPECT_EQW;
739 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
740 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
741 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
742 EXPECT_LENW; EXPECT_EQW;
744 /* try to convert formatting strings with more than two letters
745 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
746 * NOTE: We expect any letter for which there is an upper case value
747 * we should see a replacement. For letters that DO NOT have
748 * upper case values we should see NO REPLACEMENT.
750 curtime.wHour = 8;
751 curtime.wMinute = 56;
752 curtime.wSecond = 13;
753 curtime.wMilliseconds = 22;
754 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
755 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
756 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
757 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
758 EXPECT_LENW; EXPECT_EQW;
760 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
761 lstrcpyW(buffer, Expected);
762 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
763 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
764 EXPECT_EQW;
766 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
767 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
768 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
769 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
770 EXPECT_LENW; EXPECT_EQW;
772 STRINGSW("'''", "'"); /* invalid quoted string */
773 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
774 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
775 EXPECT_LENW; EXPECT_EQW;
777 /* test that msdn suggested single quotation usage works as expected */
778 STRINGSW("''''", "'"); /* single quote mark */
779 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
780 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781 EXPECT_LENW; EXPECT_EQW;
783 STRINGSW("''HHHHHH", "08"); /* Normal use */
784 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENW; EXPECT_EQW;
788 /* and test for normal use of the single quotation mark */
789 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
790 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
791 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
792 EXPECT_LENW; EXPECT_EQW;
794 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
795 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
796 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
797 EXPECT_LENW; EXPECT_EQW;
799 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
800 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
801 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
802 EXPECT_LENW; EXPECT_EQW;
804 curtime.wHour = 25;
805 STRINGSW("'123'tt", ""); /* Invalid time */
806 SetLastError(0xdeadbeef);
807 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
808 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
809 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
811 curtime.wHour = 12;
812 curtime.wMonth = 60; /* Invalid */
813 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
814 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
815 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
816 EXPECT_LENW; EXPECT_EQW;
819 static void test_GetDateFormatA(void)
821 int ret;
822 SYSTEMTIME curtime;
823 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
824 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
825 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
826 char Broken[BUFFER_SIZE];
827 char short_day[10], month[10], genitive_month[10];
829 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
830 STRINGSA("ddd',' MMM dd yy","");
831 SetLastError(0xdeadbeef);
832 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
833 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
834 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
836 curtime.wYear = 2002;
837 curtime.wMonth = 5;
838 curtime.wDay = 4;
839 curtime.wDayOfWeek = 3;
840 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
841 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
842 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
843 EXPECT_LENA; EXPECT_EQA;
845 /* Same as above but with LOCALE_NOUSEROVERRIDE */
846 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
847 SetLastError(0xdeadbeef);
848 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
849 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
850 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
851 EXPECT_EQA;
853 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
854 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
855 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
856 EXPECT_LENA; EXPECT_EQA;
858 curtime.wHour = 36; /* Invalid */
859 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
860 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
861 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
862 EXPECT_LENA; EXPECT_EQA;
864 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
865 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
866 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
867 EXPECT_EQA;
869 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
870 SetLastError(0xdeadbeef);
871 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
872 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
873 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
875 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
876 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
877 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
878 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
879 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
881 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
882 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
883 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
884 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
885 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
886 "got an unexpected date string '%s'\n", buffer);
888 /* test for expected DATE_YEARMONTH behavior with null format */
889 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
890 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
891 SetLastError(0xdeadbeef);
892 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
893 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
894 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 EXPECT_EQA;
897 /* Test that using invalid DATE_* flags results in the correct error */
898 /* and return values */
899 STRINGSA("m/d/y", ""); /* Invalid flags */
900 SetLastError(0xdeadbeef);
901 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
902 &curtime, input, buffer, COUNTOF(buffer));
903 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
904 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
906 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
907 if (!ret)
909 win_skip("LANG_RUSSIAN locale data unavailable\n");
910 return;
913 /* month part should be in genitive form */
914 strcpy(genitive_month, buffer + 2);
915 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 strcpy(month, buffer);
918 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
920 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
921 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
922 strcpy(short_day, buffer);
924 STRINGSA("dd MMMMddd dd", "");
925 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
926 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
927 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
928 EXPECT_EQA;
930 STRINGSA("MMMMddd dd", "");
931 sprintf(Expected, "%s%s 04", month, short_day);
932 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
933 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
934 EXPECT_EQA;
936 STRINGSA("MMMMddd", "");
937 sprintf(Expected, "%s%s", month, short_day);
938 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
939 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
940 EXPECT_EQA;
942 STRINGSA("MMMMdd", "");
943 sprintf(Expected, "%s04", genitive_month);
944 sprintf(Broken, "%s04", month);
945 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
948 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
949 "Expected '%s', got '%s'\n", Expected, buffer);
951 STRINGSA("MMMMdd ddd", "");
952 sprintf(Expected, "%s04 %s", genitive_month, short_day);
953 sprintf(Broken, "%s04 %s", month, short_day);
954 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
955 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
956 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
957 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
958 "Expected '%s', got '%s'\n", Expected, buffer);
960 STRINGSA("dd dddMMMM", "");
961 sprintf(Expected, "04 %s%s", short_day, month);
962 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
963 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
964 EXPECT_EQA;
966 STRINGSA("dd dddMMMM ddd MMMMdd", "");
967 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
968 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
969 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
970 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
971 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
972 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
973 "Expected '%s', got '%s'\n", Expected, buffer);
975 /* with literal part */
976 STRINGSA("ddd',' MMMM dd", "");
977 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
978 sprintf(Broken, "%s, %s 04", short_day, month);
979 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
980 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
981 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
982 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
983 "Expected '%s', got '%s'\n", Expected, buffer);
986 static void test_GetDateFormatEx(void)
988 int ret;
989 SYSTEMTIME curtime;
990 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
992 if (!pGetDateFormatEx)
994 win_skip("GetDateFormatEx not supported\n");
995 return;
998 STRINGSW("",""); /* If flags are set, then format must be NULL */
999 SetLastError(0xdeadbeef);
1000 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1001 input, buffer, COUNTOF(buffer), NULL);
1002 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1003 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1004 EXPECT_EQW;
1006 STRINGSW("",""); /* NULL buffer, len > 0 */
1007 SetLastError(0xdeadbeef);
1008 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1009 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1010 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1012 STRINGSW("",""); /* NULL buffer, len == 0 */
1013 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1014 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1015 EXPECT_LENW; EXPECT_EQW;
1017 STRINGSW("",""); /* Invalid flag combination */
1018 SetLastError(0xdeadbeef);
1019 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1020 input, NULL, 0, NULL);
1021 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1022 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1023 EXPECT_EQW;
1025 curtime.wYear = 2002;
1026 curtime.wMonth = 10;
1027 curtime.wDay = 23;
1028 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1029 curtime.wHour = 65432; /* Invalid */
1030 curtime.wMinute = 34512; /* Invalid */
1031 curtime.wSecond = 65535; /* Invalid */
1032 curtime.wMilliseconds = 12345;
1033 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1034 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1036 EXPECT_LENW; EXPECT_EQW;
1038 curtime.wYear = 2002;
1039 curtime.wMonth = 10;
1040 curtime.wDay = 23;
1041 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1042 curtime.wHour = 65432; /* Invalid */
1043 curtime.wMinute = 34512; /* Invalid */
1044 curtime.wSecond = 65535; /* Invalid */
1045 curtime.wMilliseconds = 12345;
1046 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1047 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1048 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1049 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1051 /* Limit tests */
1053 curtime.wYear = 1601;
1054 curtime.wMonth = 1;
1055 curtime.wDay = 1;
1056 curtime.wDayOfWeek = 0; /* Irrelevant */
1057 curtime.wHour = 0;
1058 curtime.wMinute = 0;
1059 curtime.wSecond = 0;
1060 curtime.wMilliseconds = 0;
1061 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1062 SetLastError(0xdeadbeef);
1063 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1064 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1065 EXPECT_LENW; EXPECT_EQW;
1067 curtime.wYear = 1600;
1068 curtime.wMonth = 12;
1069 curtime.wDay = 31;
1070 curtime.wDayOfWeek = 0; /* Irrelevant */
1071 curtime.wHour = 23;
1072 curtime.wMinute = 59;
1073 curtime.wSecond = 59;
1074 curtime.wMilliseconds = 999;
1075 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1076 SetLastError(0xdeadbeef);
1077 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1078 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1079 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1082 static void test_GetDateFormatW(void)
1084 int ret;
1085 SYSTEMTIME curtime;
1086 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1087 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1089 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1090 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1091 input, buffer, COUNTOF(buffer));
1092 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1094 win_skip("GetDateFormatW is not implemented\n");
1095 return;
1097 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1098 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1099 EXPECT_EQW;
1101 STRINGSW("",""); /* NULL buffer, len > 0 */
1102 SetLastError(0xdeadbeef);
1103 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1104 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1105 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1107 STRINGSW("",""); /* NULL buffer, len == 0 */
1108 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENW; EXPECT_EQW;
1112 curtime.wYear = 2002;
1113 curtime.wMonth = 10;
1114 curtime.wDay = 23;
1115 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1116 curtime.wHour = 65432; /* Invalid */
1117 curtime.wMinute = 34512; /* Invalid */
1118 curtime.wSecond = 65535; /* Invalid */
1119 curtime.wMilliseconds = 12345;
1120 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1121 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1122 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1123 EXPECT_LENW; EXPECT_EQW;
1125 /* Limit tests */
1127 curtime.wYear = 1601;
1128 curtime.wMonth = 1;
1129 curtime.wDay = 1;
1130 curtime.wDayOfWeek = 0; /* Irrelevant */
1131 curtime.wHour = 0;
1132 curtime.wMinute = 0;
1133 curtime.wSecond = 0;
1134 curtime.wMilliseconds = 0;
1135 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1136 SetLastError(0xdeadbeef);
1137 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1138 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1139 EXPECT_LENW; EXPECT_EQW;
1141 curtime.wYear = 1600;
1142 curtime.wMonth = 12;
1143 curtime.wDay = 31;
1144 curtime.wDayOfWeek = 0; /* Irrelevant */
1145 curtime.wHour = 23;
1146 curtime.wMinute = 59;
1147 curtime.wSecond = 59;
1148 curtime.wMilliseconds = 999;
1149 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1150 SetLastError(0xdeadbeef);
1151 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1152 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1153 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1157 #define CY_POS_LEFT 0
1158 #define CY_POS_RIGHT 1
1159 #define CY_POS_LEFT_SPACE 2
1160 #define CY_POS_RIGHT_SPACE 3
1162 static void test_GetCurrencyFormatA(void)
1164 static char szDot[] = { '.', '\0' };
1165 static char szComma[] = { ',', '\0' };
1166 static char szDollar[] = { '$', '\0' };
1167 int ret;
1168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1169 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1170 CURRENCYFMTA format;
1172 memset(&format, 0, sizeof(format));
1174 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1175 SetLastError(0xdeadbeef);
1176 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1177 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1178 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1180 STRINGSA("23,53",""); /* Invalid character --> Error */
1181 SetLastError(0xdeadbeef);
1182 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1183 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1184 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1186 STRINGSA("--",""); /* Double '-' --> Error */
1187 SetLastError(0xdeadbeef);
1188 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1189 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1190 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1192 STRINGSA("0-",""); /* Trailing '-' --> Error */
1193 SetLastError(0xdeadbeef);
1194 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1195 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1196 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1198 STRINGSA("0..",""); /* Double '.' --> Error */
1199 SetLastError(0xdeadbeef);
1200 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1201 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1202 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1204 STRINGSA(" 0.1",""); /* Leading space --> Error */
1205 SetLastError(0xdeadbeef);
1206 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1207 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1208 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1210 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1211 SetLastError(0xdeadbeef);
1212 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1213 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1214 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1216 STRINGSA("2353",""); /* Format and flags given --> Error */
1217 SetLastError(0xdeadbeef);
1218 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1219 ok( !ret, "Expected ret == 0, got %d\n", ret);
1220 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1221 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1223 STRINGSA("2353",""); /* Invalid format --> Error */
1224 SetLastError(0xdeadbeef);
1225 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1226 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1227 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1229 STRINGSA("2353","$2,353.00"); /* Valid number */
1230 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1231 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1232 EXPECT_LENA; EXPECT_EQA;
1234 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1235 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1237 EXPECT_LENA; EXPECT_EQA;
1239 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1240 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1241 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1242 EXPECT_LENA; EXPECT_EQA;
1244 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1245 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1246 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1247 EXPECT_LENA; EXPECT_EQA;
1249 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1250 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1251 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1252 EXPECT_LENA; EXPECT_EQA;
1254 format.NumDigits = 0; /* No decimal separator */
1255 format.LeadingZero = 0;
1256 format.Grouping = 0; /* No grouping char */
1257 format.NegativeOrder = 0;
1258 format.PositiveOrder = CY_POS_LEFT;
1259 format.lpDecimalSep = szDot;
1260 format.lpThousandSep = szComma;
1261 format.lpCurrencySymbol = szDollar;
1263 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1264 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1265 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1266 EXPECT_LENA; EXPECT_EQA;
1268 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1269 STRINGSA("2353","$2353.0");
1270 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1271 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1272 EXPECT_LENA; EXPECT_EQA;
1274 format.Grouping = 2; /* Group by 100's */
1275 STRINGSA("2353","$23,53.0");
1276 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1277 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1278 EXPECT_LENA; EXPECT_EQA;
1280 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1281 format.Grouping = 3;
1282 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1283 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1284 EXPECT_LENA; EXPECT_EQA;
1286 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1287 format.NegativeOrder = 2;
1288 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1289 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1290 EXPECT_LENA; EXPECT_EQA;
1292 format.LeadingZero = 1; /* Always provide leading zero */
1293 STRINGSA(".5","$0.5");
1294 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1295 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1296 EXPECT_LENA; EXPECT_EQA;
1298 format.PositiveOrder = CY_POS_RIGHT;
1299 STRINGSA("1","1.0$");
1300 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1301 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1302 EXPECT_LENA; EXPECT_EQA;
1304 format.PositiveOrder = CY_POS_LEFT_SPACE;
1305 STRINGSA("1","$ 1.0");
1306 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1307 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1308 EXPECT_LENA; EXPECT_EQA;
1310 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1311 STRINGSA("1","1.0 $");
1312 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1313 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1314 EXPECT_LENA; EXPECT_EQA;
1316 format.NegativeOrder = 0;
1317 STRINGSA("-1","($1.0)");
1318 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1319 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1320 EXPECT_LENA; EXPECT_EQA;
1322 format.NegativeOrder = 1;
1323 STRINGSA("-1","-$1.0");
1324 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1326 EXPECT_LENA; EXPECT_EQA;
1328 format.NegativeOrder = 2;
1329 STRINGSA("-1","$-1.0");
1330 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1331 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1332 EXPECT_LENA; EXPECT_EQA;
1334 format.NegativeOrder = 3;
1335 STRINGSA("-1","$1.0-");
1336 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1337 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1338 EXPECT_LENA; EXPECT_EQA;
1340 format.NegativeOrder = 4;
1341 STRINGSA("-1","(1.0$)");
1342 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1343 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1344 EXPECT_LENA; EXPECT_EQA;
1346 format.NegativeOrder = 5;
1347 STRINGSA("-1","-1.0$");
1348 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1349 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1350 EXPECT_LENA; EXPECT_EQA;
1352 format.NegativeOrder = 6;
1353 STRINGSA("-1","1.0-$");
1354 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1355 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1356 EXPECT_LENA; EXPECT_EQA;
1358 format.NegativeOrder = 7;
1359 STRINGSA("-1","1.0$-");
1360 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1361 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1362 EXPECT_LENA; EXPECT_EQA;
1364 format.NegativeOrder = 8;
1365 STRINGSA("-1","-1.0 $");
1366 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1368 EXPECT_LENA; EXPECT_EQA;
1370 format.NegativeOrder = 9;
1371 STRINGSA("-1","-$ 1.0");
1372 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1373 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1374 EXPECT_LENA; EXPECT_EQA;
1376 format.NegativeOrder = 10;
1377 STRINGSA("-1","1.0 $-");
1378 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1379 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1380 EXPECT_LENA; EXPECT_EQA;
1382 format.NegativeOrder = 11;
1383 STRINGSA("-1","$ 1.0-");
1384 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1385 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1386 EXPECT_LENA; EXPECT_EQA;
1388 format.NegativeOrder = 12;
1389 STRINGSA("-1","$ -1.0");
1390 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1391 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1392 EXPECT_LENA; EXPECT_EQA;
1394 format.NegativeOrder = 13;
1395 STRINGSA("-1","1.0- $");
1396 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1397 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1398 EXPECT_LENA; EXPECT_EQA;
1400 format.NegativeOrder = 14;
1401 STRINGSA("-1","($ 1.0)");
1402 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1403 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1404 EXPECT_LENA; EXPECT_EQA;
1406 format.NegativeOrder = 15;
1407 STRINGSA("-1","(1.0 $)");
1408 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1409 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1410 EXPECT_LENA; EXPECT_EQA;
1413 #define NEG_PARENS 0 /* "(1.1)" */
1414 #define NEG_LEFT 1 /* "-1.1" */
1415 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1416 #define NEG_RIGHT 3 /* "1.1-" */
1417 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1419 static void test_GetNumberFormatA(void)
1421 static char szDot[] = { '.', '\0' };
1422 static char szComma[] = { ',', '\0' };
1423 int ret;
1424 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1425 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1426 NUMBERFMTA format;
1428 memset(&format, 0, sizeof(format));
1430 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1431 SetLastError(0xdeadbeef);
1432 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1433 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1434 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1436 STRINGSA("23,53",""); /* Invalid character --> Error */
1437 SetLastError(0xdeadbeef);
1438 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1442 STRINGSA("--",""); /* Double '-' --> Error */
1443 SetLastError(0xdeadbeef);
1444 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1445 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1448 STRINGSA("0-",""); /* Trailing '-' --> Error */
1449 SetLastError(0xdeadbeef);
1450 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1451 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1452 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1454 STRINGSA("0..",""); /* Double '.' --> Error */
1455 SetLastError(0xdeadbeef);
1456 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1457 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1458 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1460 STRINGSA(" 0.1",""); /* Leading space --> Error */
1461 SetLastError(0xdeadbeef);
1462 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1463 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1464 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1466 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1467 SetLastError(0xdeadbeef);
1468 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1469 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1470 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1472 STRINGSA("2353",""); /* Format and flags given --> Error */
1473 SetLastError(0xdeadbeef);
1474 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1475 ok( !ret, "Expected ret == 0, got %d\n", ret);
1476 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1477 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1479 STRINGSA("2353",""); /* Invalid format --> Error */
1480 SetLastError(0xdeadbeef);
1481 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1482 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1483 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1485 STRINGSA("2353","2,353.00"); /* Valid number */
1486 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1488 EXPECT_LENA; EXPECT_EQA;
1490 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1491 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1493 EXPECT_LENA; EXPECT_EQA;
1495 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1496 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1498 EXPECT_LENA; EXPECT_EQA;
1500 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1501 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1503 EXPECT_LENA; EXPECT_EQA;
1505 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1506 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1507 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1508 EXPECT_LENA; EXPECT_EQA;
1510 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1511 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1512 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1513 EXPECT_LENA; EXPECT_EQA;
1515 format.NumDigits = 0; /* No decimal separator */
1516 format.LeadingZero = 0;
1517 format.Grouping = 0; /* No grouping char */
1518 format.NegativeOrder = 0;
1519 format.lpDecimalSep = szDot;
1520 format.lpThousandSep = szComma;
1522 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1523 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1525 EXPECT_LENA; EXPECT_EQA;
1527 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1528 STRINGSA("2353","2353.0");
1529 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1531 EXPECT_LENA; EXPECT_EQA;
1533 format.Grouping = 2; /* Group by 100's */
1534 STRINGSA("2353","23,53.0");
1535 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1536 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1537 EXPECT_LENA; EXPECT_EQA;
1539 STRINGSA("235","235.0"); /* Grouping of a positive number */
1540 format.Grouping = 3;
1541 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1543 EXPECT_LENA; EXPECT_EQA;
1545 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1546 format.NegativeOrder = NEG_LEFT;
1547 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1548 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1549 EXPECT_LENA; EXPECT_EQA;
1551 format.LeadingZero = 1; /* Always provide leading zero */
1552 STRINGSA(".5","0.5");
1553 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1554 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1555 EXPECT_LENA; EXPECT_EQA;
1557 format.NegativeOrder = NEG_PARENS;
1558 STRINGSA("-1","(1.0)");
1559 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1561 EXPECT_LENA; EXPECT_EQA;
1563 format.NegativeOrder = NEG_LEFT;
1564 STRINGSA("-1","-1.0");
1565 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1567 EXPECT_LENA; EXPECT_EQA;
1569 format.NegativeOrder = NEG_LEFT_SPACE;
1570 STRINGSA("-1","- 1.0");
1571 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1573 EXPECT_LENA; EXPECT_EQA;
1575 format.NegativeOrder = NEG_RIGHT;
1576 STRINGSA("-1","1.0-");
1577 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1579 EXPECT_LENA; EXPECT_EQA;
1581 format.NegativeOrder = NEG_RIGHT_SPACE;
1582 STRINGSA("-1","1.0 -");
1583 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1585 EXPECT_LENA; EXPECT_EQA;
1587 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1589 if (IsValidLocale(lcid, 0))
1591 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1592 Expected[3] = 160; /* Non breaking space */
1593 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1595 EXPECT_LENA; EXPECT_EQA;
1599 struct comparestringa_entry {
1600 LCID lcid;
1601 DWORD flags;
1602 const char *first;
1603 int first_len;
1604 const char *second;
1605 int second_len;
1606 int ret;
1609 static const struct comparestringa_entry comparestringa_data[] = {
1610 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1611 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1612 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1613 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1614 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1615 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1616 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1617 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1618 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1619 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1620 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1621 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1622 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1623 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1624 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1625 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1626 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1627 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1628 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1629 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1630 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1631 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1632 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1633 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1634 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1635 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1636 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1637 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1638 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1639 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1642 static void test_CompareStringA(void)
1644 int ret, i;
1645 char a[256];
1646 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1648 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1650 const struct comparestringa_entry *entry = &comparestringa_data[i];
1652 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1653 entry->second, entry->second_len);
1654 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1657 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1658 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1660 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1661 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1663 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1664 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1666 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1667 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1669 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1671 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1672 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1674 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1675 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1677 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1678 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1680 /* test for CompareStringA flags */
1681 SetLastError(0xdeadbeef);
1682 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1683 ok(GetLastError() == ERROR_INVALID_FLAGS,
1684 "unexpected error code %d\n", GetLastError());
1685 ok(!ret, "CompareStringA must fail with invalid flag\n");
1687 SetLastError(0xdeadbeef);
1688 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1689 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1690 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1691 /* end of test for CompareStringA flags */
1693 ret = lstrcmpA("", "");
1694 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1696 ret = lstrcmpA(NULL, NULL);
1697 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1699 ret = lstrcmpA("", NULL);
1700 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1702 ret = lstrcmpA(NULL, "");
1703 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1706 if (0) { /* this requires collation table patch to make it MS compatible */
1707 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1708 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1710 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1711 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1713 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1714 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1716 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1717 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1719 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1720 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1722 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1723 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1725 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1726 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1728 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1729 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1731 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1732 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1734 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1735 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1737 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1738 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1740 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1741 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1745 /* WinXP handles embedded NULLs differently than earlier versions */
1746 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1747 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1749 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1750 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);
1752 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1753 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1755 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1756 ok(ret == CSTR_EQUAL || /* win2k */
1757 ret == CSTR_GREATER_THAN,
1758 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1760 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1761 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1763 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1764 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1766 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1767 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1769 ret = lstrcmpiA("#", ".");
1770 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1772 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1774 /* \xB9 character lies between a and b */
1775 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1776 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1777 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1778 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1780 memset(a, 'a', sizeof(a));
1781 SetLastError(0xdeadbeef);
1782 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1783 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1784 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1787 struct comparestringex_test {
1788 const char *locale;
1789 DWORD flags;
1790 const WCHAR first[2];
1791 const WCHAR second[2];
1792 INT ret;
1793 INT broken;
1794 BOOL todo;
1797 static const struct comparestringex_test comparestringex_tests[] = {
1798 /* default behavior */
1799 { /* 0 */
1800 "tr-TR", 0,
1801 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
1803 { /* 1 */
1804 "tr-TR", 0,
1805 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1807 { /* 2 */
1808 "tr-TR", 0,
1809 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1811 { /* 3 */
1812 "tr-TR", 0,
1813 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1815 { /* 4 */
1816 "tr-TR", 0,
1817 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1819 { /* 5 */
1820 "tr-TR", 0,
1821 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1823 /* with NORM_IGNORECASE */
1824 { /* 6 */
1825 "tr-TR", NORM_IGNORECASE,
1826 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
1828 { /* 7 */
1829 "tr-TR", NORM_IGNORECASE,
1830 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1832 { /* 8 */
1833 "tr-TR", NORM_IGNORECASE,
1834 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1836 { /* 9 */
1837 "tr-TR", NORM_IGNORECASE,
1838 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1840 { /* 10 */
1841 "tr-TR", NORM_IGNORECASE,
1842 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1844 { /* 11 */
1845 "tr-TR", NORM_IGNORECASE,
1846 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1848 /* with NORM_LINGUISTIC_CASING */
1849 { /* 12 */
1850 "tr-TR", NORM_LINGUISTIC_CASING,
1851 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1853 { /* 13 */
1854 "tr-TR", NORM_LINGUISTIC_CASING,
1855 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1857 { /* 14 */
1858 "tr-TR", NORM_LINGUISTIC_CASING,
1859 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1861 { /* 15 */
1862 "tr-TR", NORM_LINGUISTIC_CASING,
1863 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1865 { /* 16 */
1866 "tr-TR", NORM_LINGUISTIC_CASING,
1867 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1869 { /* 17 */
1870 "tr-TR", NORM_LINGUISTIC_CASING,
1871 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1873 /* with LINGUISTIC_IGNORECASE */
1874 { /* 18 */
1875 "tr-TR", LINGUISTIC_IGNORECASE,
1876 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
1878 { /* 19 */
1879 "tr-TR", LINGUISTIC_IGNORECASE,
1880 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1882 { /* 20 */
1883 "tr-TR", LINGUISTIC_IGNORECASE,
1884 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1886 { /* 21 */
1887 "tr-TR", LINGUISTIC_IGNORECASE,
1888 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1890 { /* 22 */
1891 "tr-TR", LINGUISTIC_IGNORECASE,
1892 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1894 { /* 23 */
1895 "tr-TR", LINGUISTIC_IGNORECASE,
1896 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1898 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
1899 { /* 24 */
1900 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1901 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1903 { /* 25 */
1904 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1905 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
1907 { /* 26 */
1908 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1909 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1911 { /* 27 */
1912 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1913 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1915 { /* 28 */
1916 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1917 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1919 { /* 29 */
1920 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1921 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1923 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
1924 { /* 30 */
1925 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1926 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1928 { /* 31 */
1929 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1930 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1932 { /* 32 */
1933 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1934 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1936 { /* 33 */
1937 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1938 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1940 { /* 34 */
1941 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1942 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1944 { /* 35 */
1945 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1946 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1950 static void test_CompareStringEx(void)
1952 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
1953 WCHAR locale[6];
1954 INT ret, i;
1956 /* CompareStringEx is only available on Vista+ */
1957 if (!pCompareStringEx)
1959 win_skip("CompareStringEx not supported\n");
1960 return;
1963 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
1965 const struct comparestringex_test *e = &comparestringex_tests[i];
1967 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
1968 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
1969 if (e->todo)
1971 todo_wine ok(ret == e->ret || broken(ret == e->broken),
1972 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1974 else
1976 ok(ret == e->ret || broken(ret == e->broken),
1977 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1983 static void test_LCMapStringA(void)
1985 int ret, ret2;
1986 char buf[256], buf2[256];
1987 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1988 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1989 static const char symbols_stripped[] = "justateststring1";
1991 SetLastError(0xdeadbeef);
1992 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1993 lower_case, -1, buf, sizeof(buf));
1994 ok(ret == lstrlenA(lower_case) + 1,
1995 "ret %d, error %d, expected value %d\n",
1996 ret, GetLastError(), lstrlenA(lower_case) + 1);
1997 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1999 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2000 upper_case, -1, buf, sizeof(buf));
2001 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2002 ok(GetLastError() == ERROR_INVALID_FLAGS,
2003 "unexpected error code %d\n", GetLastError());
2005 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
2006 upper_case, -1, buf, sizeof(buf));
2007 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
2008 ok(GetLastError() == ERROR_INVALID_FLAGS,
2009 "unexpected error code %d\n", GetLastError());
2011 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2012 upper_case, -1, buf, sizeof(buf));
2013 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
2014 ok(GetLastError() == ERROR_INVALID_FLAGS,
2015 "unexpected error code %d\n", GetLastError());
2017 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2018 upper_case, -1, buf, sizeof(buf));
2019 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
2020 ok(GetLastError() == ERROR_INVALID_FLAGS,
2021 "unexpected error code %d\n", GetLastError());
2023 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2024 SetLastError(0xdeadbeef);
2025 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
2026 upper_case, -1, buf, sizeof(buf));
2027 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2028 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
2030 /* test LCMAP_LOWERCASE */
2031 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2032 upper_case, -1, buf, sizeof(buf));
2033 ok(ret == lstrlenA(upper_case) + 1,
2034 "ret %d, error %d, expected value %d\n",
2035 ret, GetLastError(), lstrlenA(upper_case) + 1);
2036 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2038 /* test LCMAP_UPPERCASE */
2039 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2040 lower_case, -1, buf, sizeof(buf));
2041 ok(ret == lstrlenA(lower_case) + 1,
2042 "ret %d, error %d, expected value %d\n",
2043 ret, GetLastError(), lstrlenA(lower_case) + 1);
2044 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2046 /* test buffer overflow */
2047 SetLastError(0xdeadbeef);
2048 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2049 lower_case, -1, buf, 4);
2050 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2051 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2053 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2054 lstrcpyA(buf, lower_case);
2055 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2056 buf, -1, buf, sizeof(buf));
2057 if (!ret) /* Win9x */
2058 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2059 else
2061 ok(ret == lstrlenA(lower_case) + 1,
2062 "ret %d, error %d, expected value %d\n",
2063 ret, GetLastError(), lstrlenA(lower_case) + 1);
2064 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2066 lstrcpyA(buf, upper_case);
2067 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2068 buf, -1, buf, sizeof(buf));
2069 if (!ret) /* Win9x */
2070 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2071 else
2073 ok(ret == lstrlenA(upper_case) + 1,
2074 "ret %d, error %d, expected value %d\n",
2075 ret, GetLastError(), lstrlenA(lower_case) + 1);
2076 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2079 /* otherwise src == dst should fail */
2080 SetLastError(0xdeadbeef);
2081 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2082 buf, 10, buf, sizeof(buf));
2083 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2084 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2085 "unexpected error code %d\n", GetLastError());
2086 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2088 /* test whether '\0' is always appended */
2089 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2090 upper_case, -1, buf, sizeof(buf));
2091 ok(ret, "LCMapStringA must succeed\n");
2092 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2093 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2094 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2095 ok(ret2, "LCMapStringA must succeed\n");
2096 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2097 ok(ret == ret2, "lengths of sort keys must be equal\n");
2098 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2100 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2101 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2102 upper_case, -1, buf, sizeof(buf));
2103 ok(ret, "LCMapStringA must succeed\n");
2104 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2105 lower_case, -1, buf2, sizeof(buf2));
2106 ok(ret2, "LCMapStringA must succeed\n");
2107 ok(ret == ret2, "lengths of sort keys must be equal\n");
2108 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2110 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2111 results from plain LCMAP_SORTKEY on Vista */
2113 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2114 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2115 lower_case, -1, buf, sizeof(buf));
2116 ok(ret, "LCMapStringA must succeed\n");
2117 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2118 symbols_stripped, -1, buf2, sizeof(buf2));
2119 ok(ret2, "LCMapStringA must succeed\n");
2120 ok(ret == ret2, "lengths of sort keys must be equal\n");
2121 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2123 /* test NORM_IGNORENONSPACE */
2124 lstrcpyA(buf, "foo");
2125 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2126 lower_case, -1, buf, sizeof(buf));
2127 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2128 lstrlenA(lower_case) + 1, ret);
2129 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2131 /* test NORM_IGNORESYMBOLS */
2132 lstrcpyA(buf, "foo");
2133 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2134 lower_case, -1, buf, sizeof(buf));
2135 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2136 lstrlenA(symbols_stripped) + 1, ret);
2137 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2139 /* test srclen = 0 */
2140 SetLastError(0xdeadbeef);
2141 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2142 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2143 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2144 "unexpected error code %d\n", GetLastError());
2147 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2149 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2151 int ret, ret2;
2152 WCHAR buf[256], buf2[256];
2153 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2155 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2156 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2157 if (broken(ret))
2158 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
2159 else
2161 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
2162 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2163 func_name, GetLastError());
2166 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
2167 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2168 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
2169 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2170 func_name, GetLastError());
2172 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2173 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2174 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
2175 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2176 func_name, GetLastError());
2178 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2179 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2180 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
2181 func_name);
2182 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2183 func_name, GetLastError());
2185 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2186 SetLastError(0xdeadbeef);
2187 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
2188 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2189 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
2190 func_name, GetLastError());
2191 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
2193 /* test LCMAP_LOWERCASE */
2194 ret = func_ptr(LCMAP_LOWERCASE,
2195 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2196 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2197 ret, GetLastError(), lstrlenW(upper_case) + 1);
2198 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2200 /* test LCMAP_UPPERCASE */
2201 ret = func_ptr(LCMAP_UPPERCASE,
2202 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2203 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2204 ret, GetLastError(), lstrlenW(lower_case) + 1);
2205 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2207 /* test buffer overflow */
2208 SetLastError(0xdeadbeef);
2209 ret = func_ptr(LCMAP_UPPERCASE,
2210 lower_case, -1, buf, 4);
2211 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2212 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2214 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2215 lstrcpyW(buf, lower_case);
2216 ret = func_ptr(LCMAP_UPPERCASE,
2217 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2218 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2219 ret, GetLastError(), lstrlenW(lower_case) + 1);
2220 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2222 lstrcpyW(buf, upper_case);
2223 ret = func_ptr(LCMAP_LOWERCASE,
2224 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2225 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2226 ret, GetLastError(), lstrlenW(lower_case) + 1);
2227 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2229 /* otherwise src == dst should fail */
2230 SetLastError(0xdeadbeef);
2231 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2232 buf, 10, buf, sizeof(buf));
2233 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2234 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2235 "%s unexpected error code %d\n", func_name, GetLastError());
2236 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2238 /* test whether '\0' is always appended */
2239 ret = func_ptr(LCMAP_SORTKEY,
2240 upper_case, -1, buf, sizeof(buf));
2241 ok(ret, "%s func_ptr must succeed\n", func_name);
2242 ret2 = func_ptr(LCMAP_SORTKEY,
2243 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2244 ok(ret, "%s func_ptr must succeed\n", func_name);
2245 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2246 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2248 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2249 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2250 upper_case, -1, buf, sizeof(buf));
2251 ok(ret, "%s func_ptr must succeed\n", func_name);
2252 ret2 = func_ptr(LCMAP_SORTKEY,
2253 lower_case, -1, buf2, sizeof(buf2));
2254 ok(ret2, "%s func_ptr must succeed\n", func_name);
2255 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2256 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2258 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2259 results from plain LCMAP_SORTKEY on Vista */
2261 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2262 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2263 lower_case, -1, buf, sizeof(buf));
2264 ok(ret, "%s func_ptr must succeed\n", func_name);
2265 ret2 = func_ptr(LCMAP_SORTKEY,
2266 symbols_stripped, -1, buf2, sizeof(buf2));
2267 ok(ret2, "%s func_ptr must succeed\n", func_name);
2268 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2269 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2271 /* test NORM_IGNORENONSPACE */
2272 lstrcpyW(buf, fooW);
2273 ret = func_ptr(NORM_IGNORENONSPACE,
2274 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2275 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2276 lstrlenW(lower_case) + 1, ret);
2277 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2279 /* test NORM_IGNORESYMBOLS */
2280 lstrcpyW(buf, fooW);
2281 ret = func_ptr(NORM_IGNORESYMBOLS,
2282 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2283 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2284 lstrlenW(symbols_stripped) + 1, ret);
2285 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2287 /* test srclen = 0 */
2288 SetLastError(0xdeadbeef);
2289 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2290 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2291 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2292 "%s unexpected error code %d\n", func_name, GetLastError());
2295 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2297 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2300 static void test_LCMapStringW(void)
2302 int ret;
2303 WCHAR buf[256];
2305 trace("testing LCMapStringW\n");
2307 SetLastError(0xdeadbeef);
2308 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2309 todo_wine {
2310 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2311 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2314 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2317 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2319 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2322 static void test_LCMapStringEx(void)
2324 int ret;
2325 WCHAR buf[256];
2327 if (!pLCMapStringEx)
2329 win_skip( "LCMapStringEx not available\n" );
2330 return;
2333 trace("testing LCMapStringEx\n");
2335 SetLastError(0xdeadbeef);
2336 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2337 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2338 todo_wine {
2339 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2340 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2343 /* test reserved parameters */
2344 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2345 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2346 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2347 ret, GetLastError(), lstrlenW(upper_case) + 1);
2348 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2350 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2351 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2352 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2353 ret, GetLastError(), lstrlenW(upper_case) + 1);
2354 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2356 /* crashes on native */
2357 if(0)
2358 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2359 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2361 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2364 struct neutralsublang_name_t {
2365 WCHAR name[3];
2366 LCID lcid;
2367 int todo;
2370 static const struct neutralsublang_name_t neutralsublang_names[] = {
2371 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2372 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2373 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2374 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2375 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2376 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2377 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2378 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2379 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2380 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2381 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2382 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2383 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2384 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2385 { {0} }
2388 static void test_LocaleNameToLCID(void)
2390 LCID lcid;
2391 INT ret;
2392 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2393 static const WCHAR enW[] = {'e','n',0};
2395 if (!pLocaleNameToLCID)
2397 win_skip( "LocaleNameToLCID not available\n" );
2398 return;
2401 /* special cases */
2402 buffer[0] = 0;
2403 SetLastError(0xdeadbeef);
2404 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2405 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2406 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2407 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2408 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2409 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2411 buffer[0] = 0;
2412 SetLastError(0xdeadbeef);
2413 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2414 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2415 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2416 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2417 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2418 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2420 buffer[0] = 0;
2421 SetLastError(0xdeadbeef);
2422 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2423 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2424 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2425 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2426 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2428 /* bad name */
2429 SetLastError(0xdeadbeef);
2430 lcid = pLocaleNameToLCID(fooW, 0);
2431 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2432 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
2434 /* english neutral name */
2435 lcid = pLocaleNameToLCID(enW, 0);
2436 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2437 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2438 if (lcid)
2440 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2442 while (*ptr->name)
2444 lcid = pLocaleNameToLCID(ptr->name, 0);
2445 if (ptr->todo)
2446 todo_wine
2447 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2448 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2449 else
2450 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2451 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2453 *buffer = 0;
2454 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2455 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2456 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2457 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2459 ptr++;
2464 /* this requires collation table patch to make it MS compatible */
2465 static const char * const strings_sorted[] =
2467 "'",
2468 "-",
2469 "!",
2470 "\"",
2471 ".",
2472 ":",
2473 "\\",
2474 "_",
2475 "`",
2476 "{",
2477 "}",
2478 "+",
2479 "0",
2480 "1",
2481 "2",
2482 "3",
2483 "4",
2484 "5",
2485 "6",
2486 "7",
2487 "8",
2488 "9",
2489 "a",
2490 "A",
2491 "b",
2492 "B",
2493 "c",
2497 static const char * const strings[] =
2499 "C",
2500 "\"",
2501 "9",
2502 "'",
2503 "}",
2504 "-",
2505 "7",
2506 "+",
2507 "`",
2508 "1",
2509 "a",
2510 "5",
2511 "\\",
2512 "8",
2513 "B",
2514 "3",
2515 "_",
2516 "6",
2517 "{",
2518 "2",
2519 "c",
2520 "4",
2521 "!",
2522 "0",
2523 "A",
2524 ":",
2525 "b",
2529 static int compare_string1(const void *e1, const void *e2)
2531 const char *s1 = *(const char *const *)e1;
2532 const char *s2 = *(const char *const *)e2;
2534 return lstrcmpA(s1, s2);
2537 static int compare_string2(const void *e1, const void *e2)
2539 const char *s1 = *(const char *const *)e1;
2540 const char *s2 = *(const char *const *)e2;
2542 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2545 static int compare_string3(const void *e1, const void *e2)
2547 const char *s1 = *(const char *const *)e1;
2548 const char *s2 = *(const char *const *)e2;
2549 char key1[256], key2[256];
2551 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2552 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2553 return strcmp(key1, key2);
2556 static void test_sorting(void)
2558 char buf[256];
2559 char **str_buf = (char **)buf;
2560 int i;
2562 assert(sizeof(buf) >= sizeof(strings));
2564 /* 1. sort using lstrcmpA */
2565 memcpy(buf, strings, sizeof(strings));
2566 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2567 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2569 ok(!strcmp(strings_sorted[i], str_buf[i]),
2570 "qsort using lstrcmpA failed for element %d\n", i);
2572 /* 2. sort using CompareStringA */
2573 memcpy(buf, strings, sizeof(strings));
2574 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2575 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2577 ok(!strcmp(strings_sorted[i], str_buf[i]),
2578 "qsort using CompareStringA failed for element %d\n", i);
2580 /* 3. sort using sort keys */
2581 memcpy(buf, strings, sizeof(strings));
2582 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2583 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2585 ok(!strcmp(strings_sorted[i], str_buf[i]),
2586 "qsort using sort keys failed for element %d\n", i);
2590 static void test_FoldStringA(void)
2592 int ret, i, j;
2593 BOOL is_special;
2594 char src[256], dst[256];
2595 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2596 static const char digits_dst[] = { '1','2','3','\0' };
2597 static const char composite_src[] =
2599 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2600 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2601 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2602 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2603 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2604 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2605 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2606 0xfb,0xfc,0xfd,0xff,'\0'
2608 static const char composite_dst[] =
2610 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2611 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2612 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2613 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2614 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2615 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2616 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2617 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2618 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2619 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2620 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2621 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2622 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2623 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2624 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2626 static const char composite_dst_alt[] =
2628 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2629 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2630 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2631 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2632 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2633 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2634 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2635 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2636 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2637 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2638 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2639 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2640 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2641 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2642 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2644 static const char ligatures_src[] =
2646 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2648 static const char ligatures_dst[] =
2650 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2652 static const struct special
2654 char src;
2655 char dst[4];
2656 } foldczone_special[] =
2658 /* src dst */
2659 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2660 { 0x98, { 0x20, 0x7e, 0x00 } },
2661 { 0x99, { 0x54, 0x4d, 0x00 } },
2662 { 0xa0, { 0x20, 0x00 } },
2663 { 0xa8, { 0x20, 0xa8, 0x00 } },
2664 { 0xaa, { 0x61, 0x00 } },
2665 { 0xaf, { 0x20, 0xaf, 0x00 } },
2666 { 0xb2, { 0x32, 0x00 } },
2667 { 0xb3, { 0x33, 0x00 } },
2668 { 0xb4, { 0x20, 0xb4, 0x00 } },
2669 { 0xb8, { 0x20, 0xb8, 0x00 } },
2670 { 0xb9, { 0x31, 0x00 } },
2671 { 0xba, { 0x6f, 0x00 } },
2672 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2673 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2674 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2675 { 0x00 }
2678 if (!pFoldStringA)
2679 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2681 /* these tests are locale specific */
2682 if (GetACP() != 1252)
2684 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2685 return;
2688 /* MAP_FOLDDIGITS */
2689 SetLastError(0);
2690 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2691 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2693 win_skip("FoldStringA is not implemented\n");
2694 return;
2696 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2697 ok(strcmp(dst, digits_dst) == 0,
2698 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2699 for (i = 1; i < 256; i++)
2701 if (!strchr(digits_src, i))
2703 src[0] = i;
2704 src[1] = '\0';
2705 SetLastError(0);
2706 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2707 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2708 ok(dst[0] == src[0],
2709 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2713 /* MAP_EXPAND_LIGATURES */
2714 SetLastError(0);
2715 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2716 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2717 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2718 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2719 ok(strcmp(dst, ligatures_dst) == 0,
2720 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2721 for (i = 1; i < 256; i++)
2723 if (!strchr(ligatures_src, i))
2725 src[0] = i;
2726 src[1] = '\0';
2727 SetLastError(0);
2728 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2729 if (ret == 3)
2731 /* Vista */
2732 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2733 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2734 "Got %s for %d\n", dst, i);
2736 else
2738 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2739 ok(dst[0] == src[0],
2740 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2746 /* MAP_COMPOSITE */
2747 SetLastError(0);
2748 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2749 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2750 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2751 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2752 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2754 for (i = 1; i < 256; i++)
2756 if (!strchr(composite_src, i))
2758 src[0] = i;
2759 src[1] = '\0';
2760 SetLastError(0);
2761 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2762 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2763 ok(dst[0] == src[0],
2764 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2765 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2769 /* MAP_FOLDCZONE */
2770 for (i = 1; i < 256; i++)
2772 src[0] = i;
2773 src[1] = '\0';
2774 SetLastError(0);
2775 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2776 is_special = FALSE;
2777 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2779 if (foldczone_special[j].src == src[0])
2781 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2782 "Expected ret == 2 or %d, got %d, error %d\n",
2783 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2784 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2785 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2786 (unsigned char)src[0]);
2787 is_special = TRUE;
2790 if (! is_special)
2792 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2793 ok(src[0] == dst[0],
2794 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2795 (unsigned char)src[0], (unsigned char)dst[0]);
2799 /* MAP_PRECOMPOSED */
2800 for (i = 1; i < 256; i++)
2802 src[0] = i;
2803 src[1] = '\0';
2804 SetLastError(0);
2805 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2806 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2807 ok(src[0] == dst[0],
2808 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2809 (unsigned char)src[0], (unsigned char)dst[0]);
2813 static void test_FoldStringW(void)
2815 int ret;
2816 unsigned int i, j;
2817 WCHAR src[256], dst[256], ch, prev_ch = 1;
2818 static const DWORD badFlags[] =
2821 MAP_PRECOMPOSED|MAP_COMPOSITE,
2822 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2823 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2825 /* Ranges of digits 0-9 : Must be sorted! */
2826 static const WCHAR digitRanges[] =
2828 0x0030, /* '0'-'9' */
2829 0x0660, /* Eastern Arabic */
2830 0x06F0, /* Arabic - Hindu */
2831 0x07C0, /* Nko */
2832 0x0966, /* Devengari */
2833 0x09E6, /* Bengalii */
2834 0x0A66, /* Gurmukhi */
2835 0x0AE6, /* Gujarati */
2836 0x0B66, /* Oriya */
2837 0x0BE6, /* Tamil - No 0 */
2838 0x0C66, /* Telugu */
2839 0x0CE6, /* Kannada */
2840 0x0D66, /* Maylayalam */
2841 0x0DE6, /* Sinhala Lith */
2842 0x0E50, /* Thai */
2843 0x0ED0, /* Laos */
2844 0x0F20, /* Tibet */
2845 0x0F29, /* Tibet half - 0 is out of sequence */
2846 0x1040, /* Myanmar */
2847 0x1090, /* Myanmar Shan */
2848 0x1368, /* Ethiopic - no 0 */
2849 0x17E0, /* Khmer */
2850 0x1810, /* Mongolian */
2851 0x1946, /* Limbu */
2852 0x19D0, /* New Tai Lue */
2853 0x1A80, /* Tai Tham Hora */
2854 0x1A90, /* Tai Tham Tham */
2855 0x1B50, /* Balinese */
2856 0x1BB0, /* Sundanese */
2857 0x1C40, /* Lepcha */
2858 0x1C50, /* Ol Chiki */
2859 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2860 0x2080, /* Subscript */
2861 0x245F, /* Circled - 0 is out of sequence */
2862 0x2473, /* Bracketed */
2863 0x2487, /* Full stop */
2864 0x24F4, /* Double Circled */
2865 0x2775, /* Inverted circled - No 0 */
2866 0x277F, /* Patterned circled - No 0 */
2867 0x2789, /* Inverted Patterned circled - No 0 */
2868 0x3020, /* Hangzhou */
2869 0xA620, /* Vai */
2870 0xA8D0, /* Saurashtra */
2871 0xA900, /* Kayah Li */
2872 0xA9D0, /* Javanese */
2873 0xA9F0, /* Myanmar Tai Laing */
2874 0xAA50, /* Cham */
2875 0xABF0, /* Meetei Mayek */
2876 0xff10, /* Pliene chasse (?) */
2877 0xffff /* Terminator */
2879 /* Digits which are represented, but out of sequence */
2880 static const WCHAR outOfSequenceDigits[] =
2882 0xB9, /* Superscript 1 */
2883 0xB2, /* Superscript 2 */
2884 0xB3, /* Superscript 3 */
2885 0x0C78, /* Telugu Fraction 0 */
2886 0x0C79, /* Telugu Fraction 1 */
2887 0x0C7A, /* Telugu Fraction 2 */
2888 0x0C7B, /* Telugu Fraction 3 */
2889 0x0C7C, /* Telugu Fraction 1 */
2890 0x0C7D, /* Telugu Fraction 2 */
2891 0x0C7E, /* Telugu Fraction 3 */
2892 0x0F33, /* Tibetan half zero */
2893 0x19DA, /* New Tai Lue Tham 1 */
2894 0x24EA, /* Circled 0 */
2895 0x24FF, /* Negative Circled 0 */
2896 0x3007, /* Ideographic number zero */
2897 '\0' /* Terminator */
2899 /* Digits in digitRanges for which no representation is available */
2900 static const WCHAR noDigitAvailable[] =
2902 0x0BE6, /* No Tamil 0 */
2903 0x0F29, /* No Tibetan half zero (out of sequence) */
2904 0x1368, /* No Ethiopic 0 */
2905 0x2473, /* No Bracketed 0 */
2906 0x2487, /* No 0 Full stop */
2907 0x24F4, /* No double circled 0 */
2908 0x2775, /* No inverted circled 0 */
2909 0x277F, /* No patterned circled */
2910 0x2789, /* No inverted Patterned circled */
2911 0x3020, /* No Hangzhou 0 */
2912 '\0' /* Terminator */
2914 static const WCHAR foldczone_src[] =
2916 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2917 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2919 static const WCHAR foldczone_dst[] =
2921 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2923 static const WCHAR foldczone_todo_src[] =
2925 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2927 static const WCHAR foldczone_todo_dst[] =
2929 0x3cb,0x1f0,' ','a',0
2931 static const WCHAR foldczone_todo_broken_dst[] =
2933 0x3cb,0x1f0,0xa0,0xaa,0
2935 static const WCHAR ligatures_src[] =
2937 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2938 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2939 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2940 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2941 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2942 0xfb04, 0xfb05, 0xfb06, '\0'
2944 static const WCHAR ligatures_dst[] =
2946 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2947 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2948 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2949 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2950 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2951 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2954 if (!pFoldStringW)
2956 win_skip("FoldStringW is not available\n");
2957 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2960 /* Invalid flag combinations */
2961 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2963 src[0] = dst[0] = '\0';
2964 SetLastError(0);
2965 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2966 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2968 win_skip("FoldStringW is not implemented\n");
2969 return;
2971 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2972 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2975 /* src & dst cannot be the same */
2976 SetLastError(0);
2977 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2978 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2979 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2981 /* src can't be NULL */
2982 SetLastError(0);
2983 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2984 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2985 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2987 /* srclen can't be 0 */
2988 SetLastError(0);
2989 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2990 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2991 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2993 /* dstlen can't be < 0 */
2994 SetLastError(0);
2995 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2996 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2997 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2999 /* Ret includes terminating NUL which is appended if srclen = -1 */
3000 SetLastError(0);
3001 src[0] = 'A';
3002 src[1] = '\0';
3003 dst[0] = '\0';
3004 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3005 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3006 ok(dst[0] == 'A' && dst[1] == '\0',
3007 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3008 'A', '\0', ret, dst[0], dst[1], GetLastError());
3010 /* If size is given, result is not NUL terminated */
3011 SetLastError(0);
3012 src[0] = 'A';
3013 src[1] = 'A';
3014 dst[0] = 'X';
3015 dst[1] = 'X';
3016 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3017 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3018 ok(dst[0] == 'A' && dst[1] == 'X',
3019 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3020 'A','X', ret, dst[0], dst[1], GetLastError());
3022 /* MAP_FOLDDIGITS */
3023 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3025 /* Check everything before this range */
3026 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3028 SetLastError(0);
3029 src[0] = ch;
3030 src[1] = dst[0] = '\0';
3031 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3032 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3034 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3035 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3036 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3037 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3038 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3039 "char %04x should not be a digit\n", ch );
3042 if (digitRanges[j] == 0xffff)
3043 break; /* Finished the whole code point space */
3045 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3047 WCHAR c;
3049 /* Map out of sequence characters */
3050 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3051 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3052 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3053 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3054 else c = ch;
3055 SetLastError(0);
3056 src[0] = c;
3057 src[1] = dst[0] = '\0';
3058 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3059 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3061 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3062 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3063 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3064 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3065 strchrW(noDigitAvailable, c),
3066 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3067 ch, '0' + digitRanges[j] - ch, dst[0]);
3069 prev_ch = ch;
3072 /* MAP_FOLDCZONE */
3073 SetLastError(0);
3074 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3075 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3076 "Got %d, error %d\n", ret, GetLastError());
3077 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3078 "MAP_FOLDCZONE: Expanded incorrectly\n");
3080 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3081 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3082 "Got %d, error %d\n", ret, GetLastError());
3083 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3084 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3085 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3087 /* MAP_EXPAND_LIGATURES */
3088 SetLastError(0);
3089 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3090 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3091 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3092 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3093 "Got %d, error %d\n", ret, GetLastError());
3094 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3095 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3098 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3103 #define LCID_OK(l) \
3104 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3105 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3106 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3107 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3108 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3110 static void test_ConvertDefaultLocale(void)
3112 LCID lcid;
3114 /* Doesn't change lcid, even if non default sublang/sort used */
3115 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3116 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3117 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3118 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3120 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3121 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3122 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3123 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3124 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3126 /* Invariant language is not treated specially */
3127 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3129 /* User/system default languages alone are not mapped */
3130 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3131 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3133 /* Default lcids */
3134 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3135 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3136 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3137 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3138 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3139 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3142 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3143 DWORD dwFlags, LONG_PTR lParam)
3145 if (winetest_debug > 1)
3146 trace("%08x, %s, %s, %08x, %08lx\n",
3147 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3149 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3150 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3152 /* If lParam is one, we are calling with flags defaulted from 0 */
3153 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3154 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3156 return TRUE;
3159 static void test_EnumSystemLanguageGroupsA(void)
3161 BOOL ret;
3163 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3165 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3166 return;
3169 /* No enumeration proc */
3170 SetLastError(0);
3171 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3172 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3174 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3175 return;
3177 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3178 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3180 /* Invalid flags */
3181 SetLastError(0);
3182 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3183 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3185 /* No flags - defaults to LGRPID_INSTALLED */
3186 SetLastError(0xdeadbeef);
3187 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3188 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3190 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3191 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3194 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3196 if (winetest_debug > 1)
3197 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3198 return TRUE;
3201 static void test_EnumSystemLocalesEx(void)
3203 BOOL ret;
3205 if (!pEnumSystemLocalesEx)
3207 win_skip( "EnumSystemLocalesEx not available\n" );
3208 return;
3210 SetLastError( 0xdeadbeef );
3211 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3212 ok( !ret, "should have failed\n" );
3213 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3214 SetLastError( 0xdeadbeef );
3215 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3216 ok( ret, "failed err %u\n", GetLastError() );
3219 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3220 LONG_PTR lParam)
3222 if (winetest_debug > 1)
3223 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3225 /* invalid locale enumerated on some platforms */
3226 if (lcid == 0)
3227 return TRUE;
3229 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3230 "Enumerated grp %d not valid\n", lgrpid);
3231 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3232 "Enumerated grp locale %04x not valid\n", lcid);
3233 return TRUE;
3236 static void test_EnumLanguageGroupLocalesA(void)
3238 BOOL ret;
3240 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3242 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3243 return;
3246 /* No enumeration proc */
3247 SetLastError(0);
3248 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3249 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3251 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3252 return;
3254 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3255 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3257 /* lgrpid too small */
3258 SetLastError(0);
3259 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3260 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3261 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3263 /* lgrpid too big */
3264 SetLastError(0);
3265 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3266 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3267 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3269 /* dwFlags is reserved */
3270 SetLastError(0);
3271 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3272 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3273 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3275 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3278 static void test_SetLocaleInfoA(void)
3280 BOOL bRet;
3281 LCID lcid = GetUserDefaultLCID();
3283 /* Null data */
3284 SetLastError(0);
3285 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3286 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3287 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3289 /* IDATE */
3290 SetLastError(0);
3291 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3292 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3293 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3295 /* ILDATE */
3296 SetLastError(0);
3297 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3298 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3299 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3302 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3304 if (winetest_debug > 1)
3305 trace("%s %08lx\n", value, lParam);
3306 return(TRUE);
3309 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3311 ok(!enumCount, "callback called again unexpected\n");
3312 enumCount++;
3313 return(FALSE);
3316 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3318 ok(0,"callback called unexpected\n");
3319 return(FALSE);
3322 static void test_EnumUILanguageA(void)
3324 BOOL ret;
3325 if (!pEnumUILanguagesA) {
3326 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3327 return;
3330 SetLastError(ERROR_SUCCESS);
3331 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3332 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3334 win_skip("EnumUILanguagesA is not implemented\n");
3335 return;
3337 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3339 enumCount = 0;
3340 SetLastError(ERROR_SUCCESS);
3341 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3342 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3344 SetLastError(ERROR_SUCCESS);
3345 ret = pEnumUILanguagesA(NULL, 0, 0);
3346 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3347 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3348 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3350 SetLastError(ERROR_SUCCESS);
3351 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3352 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3353 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3355 SetLastError(ERROR_SUCCESS);
3356 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3357 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3358 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3359 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3362 static char date_fmt_buf[1024];
3363 static WCHAR date_fmt_bufW[1024];
3365 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3367 lstrcatA(date_fmt_buf, fmt);
3368 lstrcatA(date_fmt_buf, "\n");
3369 return TRUE;
3372 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3374 lstrcatW(date_fmt_bufW, fmt);
3375 return FALSE;
3378 static void test_EnumDateFormatsA(void)
3380 char *p, buf[256];
3381 BOOL ret;
3382 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3384 date_fmt_buf[0] = 0;
3385 SetLastError(0xdeadbeef);
3386 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3387 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3389 win_skip("0 for dwFlags is not supported\n");
3391 else
3393 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3394 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3395 /* test the 1st enumerated format */
3396 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3397 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3398 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3399 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3402 date_fmt_buf[0] = 0;
3403 SetLastError(0xdeadbeef);
3404 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3405 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3407 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3409 else
3411 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3412 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3413 /* test the 1st enumerated format */
3414 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3415 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3416 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3417 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3420 date_fmt_buf[0] = 0;
3421 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3422 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3423 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3424 /* test the 1st enumerated format */
3425 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3426 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3427 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3428 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3430 date_fmt_buf[0] = 0;
3431 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3432 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3433 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3434 /* test the 1st enumerated format */
3435 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3436 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3437 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3438 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3440 date_fmt_buf[0] = 0;
3441 SetLastError(0xdeadbeef);
3442 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3443 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3445 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3446 return;
3448 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3449 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3450 /* test the 1st enumerated format */
3451 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3452 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3453 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3454 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3455 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3458 static void test_EnumTimeFormatsA(void)
3460 char *p, buf[256];
3461 BOOL ret;
3462 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3464 date_fmt_buf[0] = 0;
3465 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3466 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3467 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3468 /* test the 1st enumerated format */
3469 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3470 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3471 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3472 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3474 date_fmt_buf[0] = 0;
3475 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3476 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3477 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3478 /* test the 1st enumerated format */
3479 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3480 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3481 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3482 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3485 static void test_EnumTimeFormatsW(void)
3487 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3488 WCHAR bufW[256];
3489 BOOL ret;
3491 date_fmt_bufW[0] = 0;
3492 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3493 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3494 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3495 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3496 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3497 wine_dbgstr_w(bufW));
3499 date_fmt_bufW[0] = 0;
3500 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3501 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3502 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3503 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3504 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3505 wine_dbgstr_w(bufW));
3507 /* TIME_NOSECONDS is Win7+ feature */
3508 date_fmt_bufW[0] = 0;
3509 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3510 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3511 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3512 else {
3513 char buf[256];
3515 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3516 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3517 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3518 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3519 wine_dbgstr_w(bufW));
3521 /* EnumTimeFormatsA doesn't support this flag */
3522 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3523 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3524 GetLastError());
3526 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3527 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3528 GetLastError());
3530 /* And it's not supported by GetLocaleInfoA either */
3531 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3532 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3533 GetLastError());
3536 static void test_GetCPInfo(void)
3538 BOOL ret;
3539 CPINFO cpinfo;
3541 SetLastError(0xdeadbeef);
3542 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3543 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3544 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3545 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3547 SetLastError(0xdeadbeef);
3548 ret = GetCPInfo(CP_UTF7, &cpinfo);
3549 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3551 win_skip("Codepage CP_UTF7 is not installed/available\n");
3553 else
3555 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3556 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3557 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3558 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3559 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3560 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3563 SetLastError(0xdeadbeef);
3564 ret = GetCPInfo(CP_UTF8, &cpinfo);
3565 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3567 win_skip("Codepage CP_UTF8 is not installed/available\n");
3569 else
3571 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3572 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3573 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3574 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3575 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3576 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3577 "expected 4, got %u\n", cpinfo.MaxCharSize);
3582 * The CT_TYPE1 has varied over windows version.
3583 * The current target for correct behavior is windows 7.
3584 * There was a big shift between windows 2000 (first introduced) and windows Xp
3585 * Most of the old values below are from windows 2000.
3586 * A smaller subset of changes happened between windows Xp and Window vista/7
3588 static void test_GetStringTypeW(void)
3590 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3591 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3592 C1_SPACE | C1_BLANK | C1_DEFINED,
3593 C1_SPACE | C1_BLANK | C1_DEFINED,
3594 C1_SPACE | C1_BLANK | C1_DEFINED,
3595 C1_CNTRL | C1_BLANK | C1_DEFINED};
3596 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3597 C1_SPACE | C1_BLANK,
3598 C1_SPACE | C1_BLANK,
3599 C1_SPACE | C1_BLANK,
3600 C1_SPACE | C1_BLANK};
3602 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3604 /* Lu, Ll, Lt */
3605 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3606 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3607 C1_LOWER | C1_ALPHA,
3608 C1_UPPER | C1_LOWER | C1_ALPHA,
3609 C1_ALPHA};
3611 /* Sk, Sk, Mn, So, Me */
3612 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3613 /* Sc, Sm, No,*/
3614 0xffe0, 0xffe9, 0x2153};
3616 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3617 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3618 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3619 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3620 C1_ALPHA | C1_DEFINED,
3621 C1_CNTRL | C1_DEFINED,
3622 C1_PUNCT | C1_DEFINED,
3623 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3624 C1_ALPHA | C1_LOWER | C1_DEFINED,
3625 C1_ALPHA | C1_DEFINED };
3626 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3627 C1_ALPHA | C1_DEFINED,
3628 C1_CNTRL | C1_DEFINED,
3629 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3630 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3631 C1_ALPHA | C1_DEFINED,
3632 C1_DEFINED
3634 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3635 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3637 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3638 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3639 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3640 static const WCHAR lower_special[] = {0x2071, 0x207f};
3641 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3642 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3643 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3644 0xfff9, 0xfffa, 0xfffb};
3645 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3647 WORD types[20];
3648 BOOL ret;
3649 WCHAR ch;
3650 int i;
3652 /* NULL src */
3653 SetLastError(0xdeadbeef);
3654 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3655 ok(!ret, "got %d\n", ret);
3656 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3658 SetLastError(0xdeadbeef);
3659 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3660 ok(!ret, "got %d\n", ret);
3661 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3663 SetLastError(0xdeadbeef);
3664 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3665 ok(!ret, "got %d\n", ret);
3666 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3668 memset(types,0,sizeof(types));
3669 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3670 for (i = 0; i < 5; i++)
3671 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]);
3673 memset(types,0,sizeof(types));
3674 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3675 for (i = 0; i < 3; i++)
3676 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]));
3677 memset(types,0,sizeof(types));
3678 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3679 for (i = 0; i < 5; i++)
3680 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3682 memset(types,0,sizeof(types));
3683 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3684 for (i = 0; i < 8; i++)
3685 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);
3687 memset(types,0,sizeof(types));
3688 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3689 for (i = 0; i < 7; i++)
3690 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]);
3692 memset(types,0,sizeof(types));
3693 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3694 for (i = 0; i < 7; i++)
3695 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));
3698 memset(types,0,sizeof(types));
3699 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3700 for (i = 0; i < 12; i++)
3701 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);
3703 memset(types,0,sizeof(types));
3704 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3705 for (i = 0; i < 3; i++)
3706 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);
3708 memset(types,0,sizeof(types));
3709 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3710 for (i = 0; i < 2; i++)
3711 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);
3713 memset(types,0,sizeof(types));
3714 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3715 for (i = 0; i < 20; i++)
3716 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);
3718 memset(types,0,sizeof(types));
3719 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3720 for (i = 0; i < 3; i++)
3721 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 );
3723 /* surrogate pairs */
3724 ch = 0xd800;
3725 memset(types, 0, sizeof(types));
3726 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3727 if (types[0] == C3_NOTAPPLICABLE)
3728 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
3729 else {
3730 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
3732 ch = 0xdc00;
3733 memset(types, 0, sizeof(types));
3734 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3735 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
3739 static void test_IdnToNameprepUnicode(void)
3741 struct {
3742 DWORD in_len;
3743 const WCHAR in[64];
3744 DWORD ret;
3745 DWORD broken_ret;
3746 const WCHAR out[64];
3747 DWORD flags;
3748 DWORD err;
3749 DWORD todo;
3750 } test_data[] = {
3752 5, {'t','e','s','t',0},
3753 5, 5, {'t','e','s','t',0},
3754 0, 0xdeadbeef
3757 3, {'a',0xe111,'b'},
3758 0, 0, {0},
3759 0, ERROR_INVALID_NAME
3762 4, {'t',0,'e',0},
3763 0, 0, {0},
3764 0, ERROR_INVALID_NAME
3767 1, {'T',0},
3768 1, 1, {'T',0},
3769 0, 0xdeadbeef
3772 1, {0},
3773 0, 0, {0},
3774 0, ERROR_INVALID_NAME
3777 6, {' ','-','/','[',']',0},
3778 6, 6, {' ','-','/','[',']',0},
3779 0, 0xdeadbeef
3782 3, {'a','-','a'},
3783 3, 3, {'a','-','a'},
3784 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3787 3, {'a','a','-'},
3788 0, 0, {0},
3789 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3791 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3792 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3793 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3794 0, 0xdeadbeef, TRUE
3797 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3798 2, 0, {'t',0},
3799 0, 0xdeadbeef
3801 { /* Another example of incorrectly working FoldString (composition) */
3802 2, {0x3b0, 0},
3803 2, 2, {0x3b0, 0},
3804 0, 0xdeadbeef, TRUE
3807 2, {0x221, 0},
3808 0, 2, {0},
3809 0, ERROR_NO_UNICODE_TRANSLATION
3812 2, {0x221, 0},
3813 2, 2, {0x221, 0},
3814 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3817 5, {'a','.','.','a',0},
3818 0, 0, {0},
3819 0, ERROR_INVALID_NAME
3822 3, {'a','.',0},
3823 3, 3, {'a','.',0},
3824 0, 0xdeadbeef
3828 WCHAR buf[1024];
3829 DWORD i, ret, err;
3831 if (!pIdnToNameprepUnicode)
3833 win_skip("IdnToNameprepUnicode is not available\n");
3834 return;
3837 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3838 test_data[0].in_len, NULL, 0);
3839 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3841 SetLastError(0xdeadbeef);
3842 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3843 test_data[1].in_len, NULL, 0);
3844 err = GetLastError();
3845 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3846 ok(err == test_data[1].err, "err = %d\n", err);
3848 SetLastError(0xdeadbeef);
3849 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3850 buf, sizeof(buf)/sizeof(WCHAR));
3851 err = GetLastError();
3852 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3853 ok(err == 0xdeadbeef, "err = %d\n", err);
3855 SetLastError(0xdeadbeef);
3856 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3857 buf, sizeof(buf)/sizeof(WCHAR));
3858 err = GetLastError();
3859 ok(ret == 0, "ret = %d\n", ret);
3860 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3862 SetLastError(0xdeadbeef);
3863 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3864 buf, sizeof(buf)/sizeof(WCHAR));
3865 err = GetLastError();
3866 ok(ret == 0, "ret = %d\n", ret);
3867 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3869 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3870 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3871 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3873 SetLastError(0xdeadbeef);
3874 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3875 err = GetLastError();
3876 ok(ret == 0, "ret = %d\n", ret);
3877 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3879 SetLastError(0xdeadbeef);
3880 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3881 err = GetLastError();
3882 ok(ret == 0, "ret = %d\n", ret);
3883 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
3884 "err = %d\n", err);
3886 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3888 SetLastError(0xdeadbeef);
3889 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3890 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3891 err = GetLastError();
3893 if (!test_data[i].todo)
3895 ok(ret == test_data[i].ret ||
3896 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3898 else
3900 todo_wine ok(ret == test_data[i].ret ||
3901 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3903 if(ret != test_data[i].ret)
3904 continue;
3906 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3907 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3908 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3912 static void test_IdnToAscii(void)
3914 struct {
3915 DWORD in_len;
3916 const WCHAR in[64];
3917 DWORD ret;
3918 const WCHAR out[64];
3919 DWORD flags;
3920 DWORD err;
3921 } test_data[] = {
3923 5, {'T','e','s','t',0},
3924 5, {'T','e','s','t',0},
3925 0, 0xdeadbeef
3928 5, {'T','e',0x017c,'s','t',0},
3929 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3930 0, 0xdeadbeef
3933 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3934 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3935 0, 0xdeadbeef
3938 3, {0x0105,'.',0},
3939 9, {'x','n','-','-','2','d','a','.',0},
3940 0, 0xdeadbeef
3943 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3944 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3945 0, 0xdeadbeef
3948 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3949 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3950 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3951 0, 0xdeadbeef
3954 2, {0x221,0},
3955 8, {'x','n','-','-','6','l','a',0},
3956 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3960 WCHAR buf[1024];
3961 DWORD i, ret, err;
3963 if (!pIdnToAscii)
3965 win_skip("IdnToAscii is not available\n");
3966 return;
3969 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3971 SetLastError(0xdeadbeef);
3972 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3973 test_data[i].in_len, buf, sizeof(buf));
3974 err = GetLastError();
3975 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3976 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3977 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3978 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3982 static void test_IdnToUnicode(void)
3984 struct {
3985 DWORD in_len;
3986 const WCHAR in[64];
3987 DWORD ret;
3988 const WCHAR out[64];
3989 DWORD flags;
3990 DWORD err;
3991 } test_data[] = {
3993 5, {'T','e','s','.',0},
3994 5, {'T','e','s','.',0},
3995 0, 0xdeadbeef
3998 2, {0x105,0},
3999 0, {0},
4000 0, ERROR_INVALID_NAME
4003 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4004 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4005 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4006 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4007 0x05d1,0x05e8,0x05d9,0x05ea,0},
4008 0, 0xdeadbeef
4011 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4012 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4013 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4014 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4015 0, 0xdeadbeef
4018 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4019 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4020 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4021 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4022 0, {0},
4023 0, ERROR_INVALID_NAME
4026 8, {'x','n','-','-','6','l','a',0},
4027 2, {0x221,0},
4028 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4032 WCHAR buf[1024];
4033 DWORD i, ret, err;
4035 if (!pIdnToUnicode)
4037 win_skip("IdnToUnicode is not available\n");
4038 return;
4041 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4043 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4044 test_data[i].in_len, NULL, 0);
4045 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4047 SetLastError(0xdeadbeef);
4048 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4049 test_data[i].in_len, buf, sizeof(buf));
4050 err = GetLastError();
4051 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4052 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4053 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4054 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4058 static void test_GetLocaleInfoEx(void)
4060 static const WCHAR enW[] = {'e','n',0};
4061 WCHAR bufferW[80];
4062 INT ret;
4064 if (!pGetLocaleInfoEx)
4066 win_skip("GetLocaleInfoEx not supported\n");
4067 return;
4070 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4071 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4072 if (ret)
4074 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4075 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4076 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4077 static const WCHAR usaW[] = {'U','S','A',0};
4078 static const WCHAR enuW[] = {'E','N','U',0};
4079 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4080 DWORD val;
4082 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4083 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4085 SetLastError(0xdeadbeef);
4086 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4087 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4089 SetLastError(0xdeadbeef);
4090 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4091 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4093 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4094 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4095 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4097 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4098 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4099 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4101 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4102 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4103 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4105 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4106 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4107 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4108 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4110 skip("Non-English locale\n");
4112 else
4113 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4115 bufferW[0] = 0;
4116 SetLastError(0xdeadbeef);
4117 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4118 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4120 while (*ptr->name)
4122 val = 0;
4123 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4124 if (ptr->todo)
4125 todo_wine
4126 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4127 else
4128 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4129 bufferW[0] = 0;
4130 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4131 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4132 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4133 ptr++;
4138 static void test_IsValidLocaleName(void)
4140 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4141 static const WCHAR zzW[] = {'z','z',0};
4142 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4143 BOOL ret;
4145 if (!pIsValidLocaleName)
4147 win_skip("IsValidLocaleName not supported\n");
4148 return;
4151 ret = pIsValidLocaleName(enusW);
4152 ok(ret, "IsValidLocaleName failed\n");
4153 ret = pIsValidLocaleName(zzW);
4154 ok(!ret, "IsValidLocaleName should have failed\n");
4155 ret = pIsValidLocaleName(zzzzW);
4156 ok(!ret, "IsValidLocaleName should have failed\n");
4157 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4158 ok(ret, "IsValidLocaleName failed\n");
4161 static void test_CompareStringOrdinal(void)
4163 INT ret;
4164 WCHAR test1[] = { 't','e','s','t',0 };
4165 WCHAR test2[] = { 'T','e','S','t',0 };
4166 WCHAR test3[] = { 't','e','s','t','3',0 };
4167 WCHAR null1[] = { 'a',0,'a',0 };
4168 WCHAR null2[] = { 'a',0,'b',0 };
4169 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4170 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4171 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4172 WCHAR coop2[] = { 'c','o','o','p',0 };
4173 WCHAR nonascii1[] = { 0x0102,0 };
4174 WCHAR nonascii2[] = { 0x0201,0 };
4176 if (!pCompareStringOrdinal)
4178 win_skip("CompareStringOrdinal not supported\n");
4179 return;
4182 /* Check errors */
4183 SetLastError(0xdeadbeef);
4184 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4185 ok(!ret, "Got %u, expected 0\n", ret);
4186 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4187 SetLastError(0xdeadbeef);
4188 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4189 ok(!ret, "Got %u, expected 0\n", ret);
4190 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4191 SetLastError(0xdeadbeef);
4192 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4193 ok(!ret, "Got %u, expected 0\n", ret);
4194 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4196 /* Check case */
4197 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4198 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4199 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4200 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4201 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4202 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4203 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4204 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4206 /* Check different sizes */
4207 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4208 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4209 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4210 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4212 /* Check null character */
4213 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4214 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4215 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4216 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4217 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4218 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4219 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4220 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4222 /* Check ordinal behaviour */
4223 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4224 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4225 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4226 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4227 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4228 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4229 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4230 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4233 static void test_GetGeoInfo(void)
4235 char buffA[20];
4236 INT ret;
4238 if (!pGetGeoInfoA)
4240 win_skip("GetGeoInfo is not available.\n");
4241 return;
4244 /* unassigned id */
4245 SetLastError(0xdeadbeef);
4246 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4247 ok(ret == 0, "got %d\n", ret);
4248 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4250 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4251 ok(ret == 3, "got %d\n", ret);
4253 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4254 ok(ret == 4, "got %d\n", ret);
4256 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4257 ok(ret == 3, "got %d\n", ret);
4258 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4260 /* buffer pointer not NULL, length is 0 - return required length */
4261 buffA[0] = 'a';
4262 SetLastError(0xdeadbeef);
4263 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4264 ok(ret == 3, "got %d\n", ret);
4265 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4267 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4268 ok(ret == 4, "got %d\n", ret);
4269 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4271 /* shorter buffer */
4272 SetLastError(0xdeadbeef);
4273 buffA[1] = buffA[2] = 0;
4274 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4275 ok(ret == 0, "got %d\n", ret);
4276 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4277 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4279 /* GEO_NATION returns GEOID in a string form */
4280 buffA[0] = 0;
4281 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4282 ok(ret == 4, "got %d\n", ret);
4283 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4285 /* GEO_PARENT */
4286 buffA[0] = 0;
4287 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4288 if (ret == 0)
4289 win_skip("GEO_PARENT not supported.\n");
4290 else
4292 ok(ret == 6, "got %d\n", ret);
4293 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4296 buffA[0] = 0;
4297 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4298 if (ret == 0)
4299 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4300 else
4302 ok(ret == 4, "got %d\n", ret);
4303 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4306 /* try invalid type value */
4307 SetLastError(0xdeadbeef);
4308 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4309 ok(ret == 0, "got %d\n", ret);
4310 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4313 static int geoidenum_count;
4314 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4316 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4317 ok(ret == 3, "got %d for %d\n", ret, geoid);
4318 /* valid geoid starts at 2 */
4319 ok(geoid >= 2, "got geoid %d\n", geoid);
4321 return geoidenum_count++ < 5;
4324 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4326 geoidenum_count++;
4327 return TRUE;
4330 static void test_EnumSystemGeoID(void)
4332 BOOL ret;
4334 if (!pEnumSystemGeoID)
4336 win_skip("EnumSystemGeoID is not available.\n");
4337 return;
4340 SetLastError(0xdeadbeef);
4341 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4342 ok(!ret, "got %d\n", ret);
4343 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4345 SetLastError(0xdeadbeef);
4346 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4347 ok(!ret, "got %d\n", ret);
4348 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4350 SetLastError(0xdeadbeef);
4351 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4352 ok(!ret, "got %d\n", ret);
4353 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4355 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4356 ok(ret, "got %d\n", ret);
4358 /* only the first level is enumerated, not the whole hierarchy */
4359 geoidenum_count = 0;
4360 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4361 if (ret == 0)
4362 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4363 else
4364 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4366 geoidenum_count = 0;
4367 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4368 if (ret == 0)
4369 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4370 else
4372 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4374 geoidenum_count = 0;
4375 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4376 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4380 struct invariant_entry {
4381 const char *name;
4382 int id;
4383 const char *expect;
4386 #define X(x) #x, x
4387 static const struct invariant_entry invariant_list[] = {
4388 { X(LOCALE_ILANGUAGE), "007f" },
4389 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4390 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4391 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4392 { X(LOCALE_ICOUNTRY), "1" },
4393 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4394 { X(LOCALE_SABBREVCTRYNAME), "IVC" },
4395 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4396 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4397 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4398 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4399 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4400 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4401 { X(LOCALE_SLIST), "," },
4402 { X(LOCALE_IMEASURE), "0" },
4403 { X(LOCALE_SDECIMAL), "." },
4404 { X(LOCALE_STHOUSAND), "," },
4405 { X(LOCALE_SGROUPING), "3;0" },
4406 { X(LOCALE_IDIGITS), "2" },
4407 { X(LOCALE_ILZERO), "1" },
4408 { X(LOCALE_INEGNUMBER), "1" },
4409 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4410 { X(LOCALE_SCURRENCY), "\x00a4" },
4411 { X(LOCALE_SINTLSYMBOL), "XDR" },
4412 { X(LOCALE_SMONDECIMALSEP), "." },
4413 { X(LOCALE_SMONTHOUSANDSEP), "," },
4414 { X(LOCALE_SMONGROUPING), "3;0" },
4415 { X(LOCALE_ICURRDIGITS), "2" },
4416 { X(LOCALE_IINTLCURRDIGITS), "2" },
4417 { X(LOCALE_ICURRENCY), "0" },
4418 { X(LOCALE_INEGCURR), "0" },
4419 { X(LOCALE_SDATE), "/" },
4420 { X(LOCALE_STIME), ":" },
4421 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4422 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4423 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4424 { X(LOCALE_IDATE), "0" },
4425 { X(LOCALE_ILDATE), "1" },
4426 { X(LOCALE_ITIME), "1" },
4427 { X(LOCALE_ITIMEMARKPOSN), "0" },
4428 { X(LOCALE_ICENTURY), "1" },
4429 { X(LOCALE_ITLZERO), "1" },
4430 { X(LOCALE_IDAYLZERO), "1" },
4431 { X(LOCALE_IMONLZERO), "1" },
4432 { X(LOCALE_S1159), "AM" },
4433 { X(LOCALE_S2359), "PM" },
4434 { X(LOCALE_ICALENDARTYPE), "1" },
4435 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4436 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4437 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4438 { X(LOCALE_SDAYNAME1), "Monday" },
4439 { X(LOCALE_SDAYNAME2), "Tuesday" },
4440 { X(LOCALE_SDAYNAME3), "Wednesday" },
4441 { X(LOCALE_SDAYNAME4), "Thursday" },
4442 { X(LOCALE_SDAYNAME5), "Friday" },
4443 { X(LOCALE_SDAYNAME6), "Saturday" },
4444 { X(LOCALE_SDAYNAME7), "Sunday" },
4445 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4446 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4447 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4448 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4449 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4450 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4451 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4452 { X(LOCALE_SMONTHNAME1), "January" },
4453 { X(LOCALE_SMONTHNAME2), "February" },
4454 { X(LOCALE_SMONTHNAME3), "March" },
4455 { X(LOCALE_SMONTHNAME4), "April" },
4456 { X(LOCALE_SMONTHNAME5), "May" },
4457 { X(LOCALE_SMONTHNAME6), "June" },
4458 { X(LOCALE_SMONTHNAME7), "July" },
4459 { X(LOCALE_SMONTHNAME8), "August" },
4460 { X(LOCALE_SMONTHNAME9), "September" },
4461 { X(LOCALE_SMONTHNAME10), "October" },
4462 { X(LOCALE_SMONTHNAME11), "November" },
4463 { X(LOCALE_SMONTHNAME12), "December" },
4464 { X(LOCALE_SMONTHNAME13), "" },
4465 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4466 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4467 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4468 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4469 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4470 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4471 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4472 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4473 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4474 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4475 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4476 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4477 { X(LOCALE_SABBREVMONTHNAME13), "" },
4478 { X(LOCALE_SPOSITIVESIGN), "+" },
4479 { X(LOCALE_SNEGATIVESIGN), "-" },
4480 { X(LOCALE_IPOSSIGNPOSN), "3" },
4481 { X(LOCALE_INEGSIGNPOSN), "0" },
4482 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4483 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4484 { X(LOCALE_INEGSYMPRECEDES), "1" },
4485 { X(LOCALE_INEGSEPBYSPACE), "0" },
4486 { X(LOCALE_SISO639LANGNAME), "iv" },
4487 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4488 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4489 { X(LOCALE_IPAPERSIZE), "9" },
4490 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4491 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4492 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4493 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4494 { X(LOCALE_SNAME), "" },
4495 { X(LOCALE_SSCRIPTS), "Latn;" },
4496 { 0 }
4498 #undef X
4500 static void test_invariant(void)
4502 int ret;
4503 int len;
4504 char buffer[BUFFER_SIZE];
4505 const struct invariant_entry *ptr = invariant_list;
4507 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4509 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4510 return;
4513 while (ptr->name)
4515 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4516 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4517 win_skip("not supported\n"); /* winxp/win2k3 */
4518 else
4520 len = strlen(ptr->expect)+1; /* include \0 */
4521 ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
4522 ptr->id, len, ret, GetLastError());
4523 ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
4524 ptr->id, ptr->expect, buffer);
4527 ptr++;
4530 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4531 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4533 skip("Non-English locale\n");
4535 else
4537 /* some locales translate these */
4538 static const char lang[] = "Invariant Language (Invariant Country)";
4539 static const char cntry[] = "Invariant Country";
4540 static const char sortm[] = "Math Alphanumerics";
4541 static const char sortd[] = "Default"; /* win2k3 */
4543 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4544 len = lstrlenA(lang) + 1;
4545 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4546 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4548 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4549 len = lstrlenA(cntry) + 1;
4550 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4551 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4553 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4554 if (ret == lstrlenA(sortm)+1)
4555 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4556 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4557 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4558 else
4559 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4560 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4564 static void test_GetSystemPreferredUILanguages(void)
4566 BOOL ret;
4567 ULONG count, size, size_id, size_name, size_buffer;
4568 WCHAR *buffer;
4571 if (!pGetSystemPreferredUILanguages)
4573 win_skip("GetSystemPreferredUILanguages is not available.\n");
4574 return;
4577 /* (in)valid first parameter */
4578 count = 0xdeadbeef;
4579 size = 0;
4580 SetLastError(0xdeadbeef);
4581 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4582 todo_wine
4583 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4584 ok(count, "Expected count > 0\n");
4585 todo_wine
4586 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4588 count = 0xdeadbeef;
4589 size = 0;
4590 SetLastError(0xdeadbeef);
4591 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4592 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4593 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4594 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4596 count = 0xdeadbeef;
4597 size = 0;
4598 SetLastError(0xdeadbeef);
4599 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4600 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4601 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4602 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4604 count = 0xdeadbeef;
4605 size = 0;
4606 SetLastError(0xdeadbeef);
4607 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
4608 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4609 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4610 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4612 count = 0xdeadbeef;
4613 size = 0;
4614 SetLastError(0xdeadbeef);
4615 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4616 todo_wine
4617 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4618 ok(count, "Expected count > 0\n");
4619 todo_wine
4620 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4622 count = 0xdeadbeef;
4623 size = 0;
4624 SetLastError(0xdeadbeef);
4625 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4626 todo_wine
4627 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4628 ok(count, "Expected count > 0\n");
4629 todo_wine
4630 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4632 /* second parameter
4633 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
4634 * -> unhandled exception c0000005
4637 /* invalid third parameter */
4638 count = 0xdeadbeef;
4639 size = 1;
4640 SetLastError(0xdeadbeef);
4641 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
4642 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4643 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4644 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4646 /* fourth parameter
4647 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
4648 * -> unhandled exception c0000005
4651 count = 0xdeadbeef;
4652 size_id = 0;
4653 SetLastError(0xdeadbeef);
4654 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
4655 todo_wine
4656 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4657 ok(count, "Expected count > 0\n");
4658 todo_wine
4659 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
4661 count = 0xdeadbeef;
4662 size_name = 0;
4663 SetLastError(0xdeadbeef);
4664 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
4665 todo_wine
4666 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4667 ok(count, "Expected count > 0\n");
4668 todo_wine
4669 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
4671 size_buffer = max(size_id, size_name);
4672 if(!size_buffer)
4674 skip("No vaild buffer size\n");
4675 return;
4678 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
4679 if (!buffer)
4681 skip("Failed to allocate memory with size %d\n", size_buffer * sizeof(WCHAR));
4682 return;
4685 count = 0xdeadbeef;
4686 size = size_buffer;
4687 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4688 SetLastError(0xdeadbeef);
4689 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4690 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4691 ok(count, "Expected count > 0\n");
4692 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4693 if (ret && size % 6 == 1)
4694 ok(!buffer[size -2] && !buffer[size -1],
4695 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4696 buffer[size -2], buffer[size -1]);
4698 count = 0xdeadbeef;
4699 size = size_buffer;
4700 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4701 SetLastError(0xdeadbeef);
4702 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4703 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4704 ok(count, "Expected count > 0\n");
4705 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4706 if (ret && size % 5 == 1)
4707 ok(!buffer[size -2] && !buffer[size -1],
4708 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4709 buffer[size -2], buffer[size -1]);
4711 count = 0xdeadbeef;
4712 size = size_buffer;
4713 SetLastError(0xdeadbeef);
4714 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
4715 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4716 ok(count, "Expected count > 0\n");
4717 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4718 if (ret && size % 5 == 1)
4719 ok(!buffer[size -2] && !buffer[size -1],
4720 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4721 buffer[size -2], buffer[size -1]);
4723 count = 0xdeadbeef;
4724 size = 0;
4725 SetLastError(0xdeadbeef);
4726 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4727 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4728 ok(count, "Expected count > 0\n");
4729 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4730 if (ret && size % 6 == 1)
4731 ok(!buffer[size -2] && !buffer[size -1],
4732 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4733 buffer[size -2], buffer[size -1]);
4735 count = 0xdeadbeef;
4736 size = 1;
4737 SetLastError(0xdeadbeef);
4738 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4739 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4740 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4741 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4743 count = 0xdeadbeef;
4744 size = size_id -1;
4745 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4746 SetLastError(0xdeadbeef);
4747 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4748 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4749 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4750 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4752 count = 0xdeadbeef;
4753 size = size_id -2;
4754 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4755 SetLastError(0xdeadbeef);
4756 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4757 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4758 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4759 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4762 START_TEST(locale)
4764 InitFunctionPointers();
4766 test_EnumTimeFormatsA();
4767 test_EnumTimeFormatsW();
4768 test_EnumDateFormatsA();
4769 test_GetLocaleInfoA();
4770 test_GetLocaleInfoW();
4771 test_GetLocaleInfoEx();
4772 test_GetTimeFormatA();
4773 test_GetTimeFormatEx();
4774 test_GetDateFormatA();
4775 test_GetDateFormatEx();
4776 test_GetDateFormatW();
4777 test_GetCurrencyFormatA(); /* Also tests the W version */
4778 test_GetNumberFormatA(); /* Also tests the W version */
4779 test_CompareStringA();
4780 test_CompareStringEx();
4781 test_LCMapStringA();
4782 test_LCMapStringW();
4783 test_LCMapStringEx();
4784 test_LocaleNameToLCID();
4785 test_FoldStringA();
4786 test_FoldStringW();
4787 test_ConvertDefaultLocale();
4788 test_EnumSystemLanguageGroupsA();
4789 test_EnumSystemLocalesEx();
4790 test_EnumLanguageGroupLocalesA();
4791 test_SetLocaleInfoA();
4792 test_EnumUILanguageA();
4793 test_GetCPInfo();
4794 test_GetStringTypeW();
4795 test_IdnToNameprepUnicode();
4796 test_IdnToAscii();
4797 test_IdnToUnicode();
4798 test_IsValidLocaleName();
4799 test_CompareStringOrdinal();
4800 test_GetGeoInfo();
4801 test_EnumSystemGeoID();
4802 test_invariant();
4803 test_GetSystemPreferredUILanguages();
4804 /* this requires collation table patch to make it MS compatible */
4805 if (0) test_sorting();