kernel32: Return a dummy value in GetSystemPreferredUILanguages.
[wine.git] / dlls / kernel32 / tests / locale.c
blobd49e0d65373b4608c8f04b49f97088a2ded8dc35
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 },
1640 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1641 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1642 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1643 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1644 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1645 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1646 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1647 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1648 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1649 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1650 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1651 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1652 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1653 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1656 static void test_CompareStringA(void)
1658 int ret, i;
1659 char a[256];
1660 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1662 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1664 const struct comparestringa_entry *entry = &comparestringa_data[i];
1666 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1667 entry->second, entry->second_len);
1668 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1671 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1672 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1674 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1675 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1677 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1678 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1680 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1681 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1683 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1685 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1686 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1688 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1689 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1691 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1692 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1694 /* test for CompareStringA flags */
1695 SetLastError(0xdeadbeef);
1696 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1697 ok(GetLastError() == ERROR_INVALID_FLAGS,
1698 "unexpected error code %d\n", GetLastError());
1699 ok(!ret, "CompareStringA must fail with invalid flag\n");
1701 SetLastError(0xdeadbeef);
1702 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1703 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1704 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1705 /* end of test for CompareStringA flags */
1707 ret = lstrcmpA("", "");
1708 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1710 ret = lstrcmpA(NULL, NULL);
1711 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1713 ret = lstrcmpA("", NULL);
1714 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1716 ret = lstrcmpA(NULL, "");
1717 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1720 if (0) { /* this requires collation table patch to make it MS compatible */
1721 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1722 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1724 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1725 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1727 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1728 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1730 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1731 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1733 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1734 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1736 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1737 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1739 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1740 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1742 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1743 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1745 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1746 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1748 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1749 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1751 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1752 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1754 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1755 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1759 /* WinXP handles embedded NULLs differently than earlier versions */
1760 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1761 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1763 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1764 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);
1766 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1767 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1769 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1770 ok(ret == CSTR_EQUAL || /* win2k */
1771 ret == CSTR_GREATER_THAN,
1772 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1774 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1775 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1777 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1778 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1780 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1781 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1783 ret = lstrcmpiA("#", ".");
1784 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1786 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1788 /* \xB9 character lies between a and b */
1789 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1790 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1791 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1792 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1794 memset(a, 'a', sizeof(a));
1795 SetLastError(0xdeadbeef);
1796 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1797 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1798 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1801 static void test_CompareStringW(void)
1803 WCHAR *str1, *str2;
1804 SYSTEM_INFO si;
1805 DWORD old_prot;
1806 BOOL success;
1807 char *buf;
1808 int ret;
1810 GetSystemInfo(&si);
1811 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1812 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1813 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1814 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1815 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1816 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1818 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
1819 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
1820 *str1 = 'A';
1821 *str2 = 'B';
1823 /* CompareStringW should abort on the first non-matching character */
1824 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
1825 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
1827 success = VirtualFree(buf, 0, MEM_RELEASE);
1828 ok(success, "VirtualFree failed with %u\n", GetLastError());
1831 struct comparestringex_test {
1832 const char *locale;
1833 DWORD flags;
1834 const WCHAR first[2];
1835 const WCHAR second[2];
1836 INT ret;
1837 INT broken;
1838 BOOL todo;
1841 static const struct comparestringex_test comparestringex_tests[] = {
1842 /* default behavior */
1843 { /* 0 */
1844 "tr-TR", 0,
1845 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
1847 { /* 1 */
1848 "tr-TR", 0,
1849 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1851 { /* 2 */
1852 "tr-TR", 0,
1853 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1855 { /* 3 */
1856 "tr-TR", 0,
1857 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1859 { /* 4 */
1860 "tr-TR", 0,
1861 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1863 { /* 5 */
1864 "tr-TR", 0,
1865 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1867 /* with NORM_IGNORECASE */
1868 { /* 6 */
1869 "tr-TR", NORM_IGNORECASE,
1870 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
1872 { /* 7 */
1873 "tr-TR", NORM_IGNORECASE,
1874 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1876 { /* 8 */
1877 "tr-TR", NORM_IGNORECASE,
1878 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1880 { /* 9 */
1881 "tr-TR", NORM_IGNORECASE,
1882 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1884 { /* 10 */
1885 "tr-TR", NORM_IGNORECASE,
1886 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1888 { /* 11 */
1889 "tr-TR", NORM_IGNORECASE,
1890 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1892 /* with NORM_LINGUISTIC_CASING */
1893 { /* 12 */
1894 "tr-TR", NORM_LINGUISTIC_CASING,
1895 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1897 { /* 13 */
1898 "tr-TR", NORM_LINGUISTIC_CASING,
1899 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1901 { /* 14 */
1902 "tr-TR", NORM_LINGUISTIC_CASING,
1903 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1905 { /* 15 */
1906 "tr-TR", NORM_LINGUISTIC_CASING,
1907 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1909 { /* 16 */
1910 "tr-TR", NORM_LINGUISTIC_CASING,
1911 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1913 { /* 17 */
1914 "tr-TR", NORM_LINGUISTIC_CASING,
1915 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1917 /* with LINGUISTIC_IGNORECASE */
1918 { /* 18 */
1919 "tr-TR", LINGUISTIC_IGNORECASE,
1920 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
1922 { /* 19 */
1923 "tr-TR", LINGUISTIC_IGNORECASE,
1924 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1926 { /* 20 */
1927 "tr-TR", LINGUISTIC_IGNORECASE,
1928 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1930 { /* 21 */
1931 "tr-TR", LINGUISTIC_IGNORECASE,
1932 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1934 { /* 22 */
1935 "tr-TR", LINGUISTIC_IGNORECASE,
1936 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1938 { /* 23 */
1939 "tr-TR", LINGUISTIC_IGNORECASE,
1940 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1942 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
1943 { /* 24 */
1944 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1945 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1947 { /* 25 */
1948 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1949 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
1951 { /* 26 */
1952 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1953 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1955 { /* 27 */
1956 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1957 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1959 { /* 28 */
1960 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1961 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1963 { /* 29 */
1964 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1965 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1967 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
1968 { /* 30 */
1969 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1970 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1972 { /* 31 */
1973 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1974 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1976 { /* 32 */
1977 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1978 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1980 { /* 33 */
1981 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1982 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1984 { /* 34 */
1985 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1986 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1988 { /* 35 */
1989 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1990 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1994 static void test_CompareStringEx(void)
1996 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
1997 WCHAR locale[6];
1998 INT ret, i;
2000 /* CompareStringEx is only available on Vista+ */
2001 if (!pCompareStringEx)
2003 win_skip("CompareStringEx not supported\n");
2004 return;
2007 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2009 const struct comparestringex_test *e = &comparestringex_tests[i];
2011 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2012 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2013 if (e->todo)
2015 todo_wine ok(ret == e->ret || broken(ret == e->broken),
2016 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2018 else
2020 ok(ret == e->ret || broken(ret == e->broken),
2021 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2027 static void test_LCMapStringA(void)
2029 int ret, ret2;
2030 char buf[256], buf2[256];
2031 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2032 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2033 static const char symbols_stripped[] = "justateststring1";
2035 SetLastError(0xdeadbeef);
2036 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2037 lower_case, -1, buf, sizeof(buf));
2038 ok(ret == lstrlenA(lower_case) + 1,
2039 "ret %d, error %d, expected value %d\n",
2040 ret, GetLastError(), lstrlenA(lower_case) + 1);
2041 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2043 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2044 upper_case, -1, buf, sizeof(buf));
2045 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2046 ok(GetLastError() == ERROR_INVALID_FLAGS,
2047 "unexpected error code %d\n", GetLastError());
2049 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
2050 upper_case, -1, buf, sizeof(buf));
2051 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
2052 ok(GetLastError() == ERROR_INVALID_FLAGS,
2053 "unexpected error code %d\n", GetLastError());
2055 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2056 upper_case, -1, buf, sizeof(buf));
2057 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
2058 ok(GetLastError() == ERROR_INVALID_FLAGS,
2059 "unexpected error code %d\n", GetLastError());
2061 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2062 upper_case, -1, buf, sizeof(buf));
2063 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
2064 ok(GetLastError() == ERROR_INVALID_FLAGS,
2065 "unexpected error code %d\n", GetLastError());
2067 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2068 SetLastError(0xdeadbeef);
2069 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
2070 upper_case, -1, buf, sizeof(buf));
2071 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2072 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
2074 /* test LCMAP_LOWERCASE */
2075 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2076 upper_case, -1, buf, sizeof(buf));
2077 ok(ret == lstrlenA(upper_case) + 1,
2078 "ret %d, error %d, expected value %d\n",
2079 ret, GetLastError(), lstrlenA(upper_case) + 1);
2080 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2082 /* test LCMAP_UPPERCASE */
2083 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2084 lower_case, -1, buf, sizeof(buf));
2085 ok(ret == lstrlenA(lower_case) + 1,
2086 "ret %d, error %d, expected value %d\n",
2087 ret, GetLastError(), lstrlenA(lower_case) + 1);
2088 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2090 /* test buffer overflow */
2091 SetLastError(0xdeadbeef);
2092 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2093 lower_case, -1, buf, 4);
2094 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2095 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2097 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2098 lstrcpyA(buf, lower_case);
2099 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2100 buf, -1, buf, sizeof(buf));
2101 if (!ret) /* Win9x */
2102 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2103 else
2105 ok(ret == lstrlenA(lower_case) + 1,
2106 "ret %d, error %d, expected value %d\n",
2107 ret, GetLastError(), lstrlenA(lower_case) + 1);
2108 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2110 lstrcpyA(buf, upper_case);
2111 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2112 buf, -1, buf, sizeof(buf));
2113 if (!ret) /* Win9x */
2114 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2115 else
2117 ok(ret == lstrlenA(upper_case) + 1,
2118 "ret %d, error %d, expected value %d\n",
2119 ret, GetLastError(), lstrlenA(lower_case) + 1);
2120 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2123 /* otherwise src == dst should fail */
2124 SetLastError(0xdeadbeef);
2125 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2126 buf, 10, buf, sizeof(buf));
2127 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2128 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2129 "unexpected error code %d\n", GetLastError());
2130 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2132 /* test whether '\0' is always appended */
2133 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2134 upper_case, -1, buf, sizeof(buf));
2135 ok(ret, "LCMapStringA must succeed\n");
2136 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2137 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2138 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2139 ok(ret2, "LCMapStringA must succeed\n");
2140 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2141 ok(ret == ret2, "lengths of sort keys must be equal\n");
2142 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2144 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2145 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2146 upper_case, -1, buf, sizeof(buf));
2147 ok(ret, "LCMapStringA must succeed\n");
2148 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2149 lower_case, -1, buf2, sizeof(buf2));
2150 ok(ret2, "LCMapStringA must succeed\n");
2151 ok(ret == ret2, "lengths of sort keys must be equal\n");
2152 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2154 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2155 results from plain LCMAP_SORTKEY on Vista */
2157 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2158 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2159 lower_case, -1, buf, sizeof(buf));
2160 ok(ret, "LCMapStringA must succeed\n");
2161 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2162 symbols_stripped, -1, buf2, sizeof(buf2));
2163 ok(ret2, "LCMapStringA must succeed\n");
2164 ok(ret == ret2, "lengths of sort keys must be equal\n");
2165 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2167 /* test NORM_IGNORENONSPACE */
2168 lstrcpyA(buf, "foo");
2169 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2170 lower_case, -1, buf, sizeof(buf));
2171 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2172 lstrlenA(lower_case) + 1, ret);
2173 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2175 /* test NORM_IGNORESYMBOLS */
2176 lstrcpyA(buf, "foo");
2177 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2178 lower_case, -1, buf, sizeof(buf));
2179 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2180 lstrlenA(symbols_stripped) + 1, ret);
2181 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2183 /* test srclen = 0 */
2184 SetLastError(0xdeadbeef);
2185 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2186 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2187 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2188 "unexpected error code %d\n", GetLastError());
2191 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2193 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2195 int ret, ret2;
2196 WCHAR buf[256], buf2[256];
2197 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2199 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2200 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2201 if (broken(ret))
2202 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
2203 else
2205 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
2206 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2207 func_name, GetLastError());
2210 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
2211 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2212 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
2213 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2214 func_name, GetLastError());
2216 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2217 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2218 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
2219 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2220 func_name, GetLastError());
2222 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2223 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2224 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
2225 func_name);
2226 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2227 func_name, GetLastError());
2229 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2230 SetLastError(0xdeadbeef);
2231 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
2232 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2233 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
2234 func_name, GetLastError());
2235 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
2237 /* test LCMAP_LOWERCASE */
2238 ret = func_ptr(LCMAP_LOWERCASE,
2239 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2240 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2241 ret, GetLastError(), lstrlenW(upper_case) + 1);
2242 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2244 /* test LCMAP_UPPERCASE */
2245 ret = func_ptr(LCMAP_UPPERCASE,
2246 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2247 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2248 ret, GetLastError(), lstrlenW(lower_case) + 1);
2249 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2251 /* test buffer overflow */
2252 SetLastError(0xdeadbeef);
2253 ret = func_ptr(LCMAP_UPPERCASE,
2254 lower_case, -1, buf, 4);
2255 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2256 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2258 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2259 lstrcpyW(buf, lower_case);
2260 ret = func_ptr(LCMAP_UPPERCASE,
2261 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2262 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2263 ret, GetLastError(), lstrlenW(lower_case) + 1);
2264 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2266 lstrcpyW(buf, upper_case);
2267 ret = func_ptr(LCMAP_LOWERCASE,
2268 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2269 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2270 ret, GetLastError(), lstrlenW(lower_case) + 1);
2271 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2273 /* otherwise src == dst should fail */
2274 SetLastError(0xdeadbeef);
2275 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2276 buf, 10, buf, sizeof(buf));
2277 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2278 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2279 "%s unexpected error code %d\n", func_name, GetLastError());
2280 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2282 /* test whether '\0' is always appended */
2283 ret = func_ptr(LCMAP_SORTKEY,
2284 upper_case, -1, buf, sizeof(buf));
2285 ok(ret, "%s func_ptr must succeed\n", func_name);
2286 ret2 = func_ptr(LCMAP_SORTKEY,
2287 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2288 ok(ret, "%s func_ptr must succeed\n", func_name);
2289 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2290 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2292 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2293 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2294 upper_case, -1, buf, sizeof(buf));
2295 ok(ret, "%s func_ptr must succeed\n", func_name);
2296 ret2 = func_ptr(LCMAP_SORTKEY,
2297 lower_case, -1, buf2, sizeof(buf2));
2298 ok(ret2, "%s func_ptr must succeed\n", func_name);
2299 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2300 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2302 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2303 results from plain LCMAP_SORTKEY on Vista */
2305 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2306 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2307 lower_case, -1, buf, sizeof(buf));
2308 ok(ret, "%s func_ptr must succeed\n", func_name);
2309 ret2 = func_ptr(LCMAP_SORTKEY,
2310 symbols_stripped, -1, buf2, sizeof(buf2));
2311 ok(ret2, "%s func_ptr must succeed\n", func_name);
2312 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2313 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2315 /* test NORM_IGNORENONSPACE */
2316 lstrcpyW(buf, fooW);
2317 ret = func_ptr(NORM_IGNORENONSPACE,
2318 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2319 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2320 lstrlenW(lower_case) + 1, ret);
2321 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2323 /* test NORM_IGNORESYMBOLS */
2324 lstrcpyW(buf, fooW);
2325 ret = func_ptr(NORM_IGNORESYMBOLS,
2326 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2327 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2328 lstrlenW(symbols_stripped) + 1, ret);
2329 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2331 /* test srclen = 0 */
2332 SetLastError(0xdeadbeef);
2333 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2334 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2335 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2336 "%s unexpected error code %d\n", func_name, GetLastError());
2339 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2341 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2344 static void test_LCMapStringW(void)
2346 int ret;
2347 WCHAR buf[256];
2349 trace("testing LCMapStringW\n");
2351 SetLastError(0xdeadbeef);
2352 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2353 todo_wine {
2354 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2355 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2358 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2361 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2363 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2366 static void test_LCMapStringEx(void)
2368 int ret;
2369 WCHAR buf[256];
2371 if (!pLCMapStringEx)
2373 win_skip( "LCMapStringEx not available\n" );
2374 return;
2377 trace("testing LCMapStringEx\n");
2379 SetLastError(0xdeadbeef);
2380 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2381 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2382 todo_wine {
2383 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2384 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2387 /* test reserved parameters */
2388 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2389 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2390 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2391 ret, GetLastError(), lstrlenW(upper_case) + 1);
2392 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2394 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2395 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2396 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2397 ret, GetLastError(), lstrlenW(upper_case) + 1);
2398 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2400 /* crashes on native */
2401 if(0)
2402 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2403 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2405 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2408 struct neutralsublang_name_t {
2409 WCHAR name[3];
2410 LCID lcid;
2411 int todo;
2414 static const struct neutralsublang_name_t neutralsublang_names[] = {
2415 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2416 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2417 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2418 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2419 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2420 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2421 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2422 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2423 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2424 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2425 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2426 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2427 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2428 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2429 { {0} }
2432 static void test_LocaleNameToLCID(void)
2434 LCID lcid;
2435 INT ret;
2436 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2437 static const WCHAR enW[] = {'e','n',0};
2439 if (!pLocaleNameToLCID)
2441 win_skip( "LocaleNameToLCID not available\n" );
2442 return;
2445 /* special cases */
2446 buffer[0] = 0;
2447 SetLastError(0xdeadbeef);
2448 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2449 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2450 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2451 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2452 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2453 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2455 buffer[0] = 0;
2456 SetLastError(0xdeadbeef);
2457 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2458 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2459 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2460 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2461 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2462 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2464 buffer[0] = 0;
2465 SetLastError(0xdeadbeef);
2466 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2467 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2468 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2469 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2470 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2472 /* bad name */
2473 SetLastError(0xdeadbeef);
2474 lcid = pLocaleNameToLCID(fooW, 0);
2475 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2476 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
2478 /* english neutral name */
2479 lcid = pLocaleNameToLCID(enW, 0);
2480 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2481 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2482 if (lcid)
2484 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2486 while (*ptr->name)
2488 lcid = pLocaleNameToLCID(ptr->name, 0);
2489 if (ptr->todo)
2490 todo_wine
2491 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2492 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2493 else
2494 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2495 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2497 *buffer = 0;
2498 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2499 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2500 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2501 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2503 ptr++;
2508 /* this requires collation table patch to make it MS compatible */
2509 static const char * const strings_sorted[] =
2511 "'",
2512 "-",
2513 "!",
2514 "\"",
2515 ".",
2516 ":",
2517 "\\",
2518 "_",
2519 "`",
2520 "{",
2521 "}",
2522 "+",
2523 "0",
2524 "1",
2525 "2",
2526 "3",
2527 "4",
2528 "5",
2529 "6",
2530 "7",
2531 "8",
2532 "9",
2533 "a",
2534 "A",
2535 "b",
2536 "B",
2537 "c",
2541 static const char * const strings[] =
2543 "C",
2544 "\"",
2545 "9",
2546 "'",
2547 "}",
2548 "-",
2549 "7",
2550 "+",
2551 "`",
2552 "1",
2553 "a",
2554 "5",
2555 "\\",
2556 "8",
2557 "B",
2558 "3",
2559 "_",
2560 "6",
2561 "{",
2562 "2",
2563 "c",
2564 "4",
2565 "!",
2566 "0",
2567 "A",
2568 ":",
2569 "b",
2573 static int compare_string1(const void *e1, const void *e2)
2575 const char *s1 = *(const char *const *)e1;
2576 const char *s2 = *(const char *const *)e2;
2578 return lstrcmpA(s1, s2);
2581 static int compare_string2(const void *e1, const void *e2)
2583 const char *s1 = *(const char *const *)e1;
2584 const char *s2 = *(const char *const *)e2;
2586 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2589 static int compare_string3(const void *e1, const void *e2)
2591 const char *s1 = *(const char *const *)e1;
2592 const char *s2 = *(const char *const *)e2;
2593 char key1[256], key2[256];
2595 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2596 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2597 return strcmp(key1, key2);
2600 static void test_sorting(void)
2602 char buf[256];
2603 char **str_buf = (char **)buf;
2604 int i;
2606 assert(sizeof(buf) >= sizeof(strings));
2608 /* 1. sort using lstrcmpA */
2609 memcpy(buf, strings, sizeof(strings));
2610 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2611 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2613 ok(!strcmp(strings_sorted[i], str_buf[i]),
2614 "qsort using lstrcmpA failed for element %d\n", i);
2616 /* 2. sort using CompareStringA */
2617 memcpy(buf, strings, sizeof(strings));
2618 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2619 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2621 ok(!strcmp(strings_sorted[i], str_buf[i]),
2622 "qsort using CompareStringA failed for element %d\n", i);
2624 /* 3. sort using sort keys */
2625 memcpy(buf, strings, sizeof(strings));
2626 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2627 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2629 ok(!strcmp(strings_sorted[i], str_buf[i]),
2630 "qsort using sort keys failed for element %d\n", i);
2634 static void test_FoldStringA(void)
2636 int ret, i, j;
2637 BOOL is_special;
2638 char src[256], dst[256];
2639 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2640 static const char digits_dst[] = { '1','2','3','\0' };
2641 static const char composite_src[] =
2643 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2644 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2645 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2646 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2647 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2648 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2649 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2650 0xfb,0xfc,0xfd,0xff,'\0'
2652 static const char composite_dst[] =
2654 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2655 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2656 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2657 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2658 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2659 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2660 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2661 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2662 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2663 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2664 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2665 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2666 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2667 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2668 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2670 static const char composite_dst_alt[] =
2672 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2673 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2674 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2675 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2676 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2677 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2678 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2679 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2680 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2681 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2682 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2683 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2684 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2685 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2686 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2688 static const char ligatures_src[] =
2690 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2692 static const char ligatures_dst[] =
2694 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2696 static const struct special
2698 char src;
2699 char dst[4];
2700 } foldczone_special[] =
2702 /* src dst */
2703 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2704 { 0x98, { 0x20, 0x7e, 0x00 } },
2705 { 0x99, { 0x54, 0x4d, 0x00 } },
2706 { 0xa0, { 0x20, 0x00 } },
2707 { 0xa8, { 0x20, 0xa8, 0x00 } },
2708 { 0xaa, { 0x61, 0x00 } },
2709 { 0xaf, { 0x20, 0xaf, 0x00 } },
2710 { 0xb2, { 0x32, 0x00 } },
2711 { 0xb3, { 0x33, 0x00 } },
2712 { 0xb4, { 0x20, 0xb4, 0x00 } },
2713 { 0xb8, { 0x20, 0xb8, 0x00 } },
2714 { 0xb9, { 0x31, 0x00 } },
2715 { 0xba, { 0x6f, 0x00 } },
2716 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2717 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2718 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2719 { 0x00 }
2722 if (!pFoldStringA)
2723 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2725 /* these tests are locale specific */
2726 if (GetACP() != 1252)
2728 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2729 return;
2732 /* MAP_FOLDDIGITS */
2733 SetLastError(0);
2734 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2735 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2737 win_skip("FoldStringA is not implemented\n");
2738 return;
2740 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2741 ok(strcmp(dst, digits_dst) == 0,
2742 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2743 for (i = 1; i < 256; i++)
2745 if (!strchr(digits_src, i))
2747 src[0] = i;
2748 src[1] = '\0';
2749 SetLastError(0);
2750 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2751 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2752 ok(dst[0] == src[0],
2753 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2757 /* MAP_EXPAND_LIGATURES */
2758 SetLastError(0);
2759 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2760 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2761 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2762 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2763 ok(strcmp(dst, ligatures_dst) == 0,
2764 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2765 for (i = 1; i < 256; i++)
2767 if (!strchr(ligatures_src, i))
2769 src[0] = i;
2770 src[1] = '\0';
2771 SetLastError(0);
2772 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2773 if (ret == 3)
2775 /* Vista */
2776 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2777 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2778 "Got %s for %d\n", dst, i);
2780 else
2782 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2783 ok(dst[0] == src[0],
2784 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2790 /* MAP_COMPOSITE */
2791 SetLastError(0);
2792 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2793 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2794 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2795 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2796 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2798 for (i = 1; i < 256; i++)
2800 if (!strchr(composite_src, i))
2802 src[0] = i;
2803 src[1] = '\0';
2804 SetLastError(0);
2805 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2806 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2807 ok(dst[0] == src[0],
2808 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2809 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2813 /* MAP_FOLDCZONE */
2814 for (i = 1; i < 256; i++)
2816 src[0] = i;
2817 src[1] = '\0';
2818 SetLastError(0);
2819 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2820 is_special = FALSE;
2821 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2823 if (foldczone_special[j].src == src[0])
2825 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2826 "Expected ret == 2 or %d, got %d, error %d\n",
2827 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2828 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2829 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2830 (unsigned char)src[0]);
2831 is_special = TRUE;
2834 if (! is_special)
2836 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2837 ok(src[0] == dst[0],
2838 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2839 (unsigned char)src[0], (unsigned char)dst[0]);
2843 /* MAP_PRECOMPOSED */
2844 for (i = 1; i < 256; i++)
2846 src[0] = i;
2847 src[1] = '\0';
2848 SetLastError(0);
2849 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2850 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2851 ok(src[0] == dst[0],
2852 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2853 (unsigned char)src[0], (unsigned char)dst[0]);
2857 static void test_FoldStringW(void)
2859 int ret;
2860 unsigned int i, j;
2861 WCHAR src[256], dst[256], ch, prev_ch = 1;
2862 static const DWORD badFlags[] =
2865 MAP_PRECOMPOSED|MAP_COMPOSITE,
2866 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2867 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2869 /* Ranges of digits 0-9 : Must be sorted! */
2870 static const WCHAR digitRanges[] =
2872 0x0030, /* '0'-'9' */
2873 0x0660, /* Eastern Arabic */
2874 0x06F0, /* Arabic - Hindu */
2875 0x07C0, /* Nko */
2876 0x0966, /* Devengari */
2877 0x09E6, /* Bengalii */
2878 0x0A66, /* Gurmukhi */
2879 0x0AE6, /* Gujarati */
2880 0x0B66, /* Oriya */
2881 0x0BE6, /* Tamil - No 0 */
2882 0x0C66, /* Telugu */
2883 0x0CE6, /* Kannada */
2884 0x0D66, /* Maylayalam */
2885 0x0DE6, /* Sinhala Lith */
2886 0x0E50, /* Thai */
2887 0x0ED0, /* Laos */
2888 0x0F20, /* Tibet */
2889 0x0F29, /* Tibet half - 0 is out of sequence */
2890 0x1040, /* Myanmar */
2891 0x1090, /* Myanmar Shan */
2892 0x1368, /* Ethiopic - no 0 */
2893 0x17E0, /* Khmer */
2894 0x1810, /* Mongolian */
2895 0x1946, /* Limbu */
2896 0x19D0, /* New Tai Lue */
2897 0x1A80, /* Tai Tham Hora */
2898 0x1A90, /* Tai Tham Tham */
2899 0x1B50, /* Balinese */
2900 0x1BB0, /* Sundanese */
2901 0x1C40, /* Lepcha */
2902 0x1C50, /* Ol Chiki */
2903 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2904 0x2080, /* Subscript */
2905 0x245F, /* Circled - 0 is out of sequence */
2906 0x2473, /* Bracketed */
2907 0x2487, /* Full stop */
2908 0x24F4, /* Double Circled */
2909 0x2775, /* Inverted circled - No 0 */
2910 0x277F, /* Patterned circled - No 0 */
2911 0x2789, /* Inverted Patterned circled - No 0 */
2912 0x3020, /* Hangzhou */
2913 0xA620, /* Vai */
2914 0xA8D0, /* Saurashtra */
2915 0xA900, /* Kayah Li */
2916 0xA9D0, /* Javanese */
2917 0xA9F0, /* Myanmar Tai Laing */
2918 0xAA50, /* Cham */
2919 0xABF0, /* Meetei Mayek */
2920 0xff10, /* Pliene chasse (?) */
2921 0xffff /* Terminator */
2923 /* Digits which are represented, but out of sequence */
2924 static const WCHAR outOfSequenceDigits[] =
2926 0xB9, /* Superscript 1 */
2927 0xB2, /* Superscript 2 */
2928 0xB3, /* Superscript 3 */
2929 0x0C78, /* Telugu Fraction 0 */
2930 0x0C79, /* Telugu Fraction 1 */
2931 0x0C7A, /* Telugu Fraction 2 */
2932 0x0C7B, /* Telugu Fraction 3 */
2933 0x0C7C, /* Telugu Fraction 1 */
2934 0x0C7D, /* Telugu Fraction 2 */
2935 0x0C7E, /* Telugu Fraction 3 */
2936 0x0F33, /* Tibetan half zero */
2937 0x19DA, /* New Tai Lue Tham 1 */
2938 0x24EA, /* Circled 0 */
2939 0x24FF, /* Negative Circled 0 */
2940 0x3007, /* Ideographic number zero */
2941 '\0' /* Terminator */
2943 /* Digits in digitRanges for which no representation is available */
2944 static const WCHAR noDigitAvailable[] =
2946 0x0BE6, /* No Tamil 0 */
2947 0x0F29, /* No Tibetan half zero (out of sequence) */
2948 0x1368, /* No Ethiopic 0 */
2949 0x2473, /* No Bracketed 0 */
2950 0x2487, /* No 0 Full stop */
2951 0x24F4, /* No double circled 0 */
2952 0x2775, /* No inverted circled 0 */
2953 0x277F, /* No patterned circled */
2954 0x2789, /* No inverted Patterned circled */
2955 0x3020, /* No Hangzhou 0 */
2956 '\0' /* Terminator */
2958 static const WCHAR foldczone_src[] =
2960 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2961 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2963 static const WCHAR foldczone_dst[] =
2965 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2967 static const WCHAR foldczone_todo_src[] =
2969 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2971 static const WCHAR foldczone_todo_dst[] =
2973 0x3cb,0x1f0,' ','a',0
2975 static const WCHAR foldczone_todo_broken_dst[] =
2977 0x3cb,0x1f0,0xa0,0xaa,0
2979 static const WCHAR ligatures_src[] =
2981 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2982 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2983 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2984 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2985 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2986 0xfb04, 0xfb05, 0xfb06, '\0'
2988 static const WCHAR ligatures_dst[] =
2990 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2991 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2992 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2993 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2994 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2995 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2998 if (!pFoldStringW)
3000 win_skip("FoldStringW is not available\n");
3001 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3004 /* Invalid flag combinations */
3005 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3007 src[0] = dst[0] = '\0';
3008 SetLastError(0);
3009 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3010 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3012 win_skip("FoldStringW is not implemented\n");
3013 return;
3015 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3016 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3019 /* src & dst cannot be the same */
3020 SetLastError(0);
3021 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3022 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3023 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3025 /* src can't be NULL */
3026 SetLastError(0);
3027 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3028 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3029 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3031 /* srclen can't be 0 */
3032 SetLastError(0);
3033 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3034 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3035 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3037 /* dstlen can't be < 0 */
3038 SetLastError(0);
3039 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3040 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3041 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3043 /* Ret includes terminating NUL which is appended if srclen = -1 */
3044 SetLastError(0);
3045 src[0] = 'A';
3046 src[1] = '\0';
3047 dst[0] = '\0';
3048 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3049 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3050 ok(dst[0] == 'A' && dst[1] == '\0',
3051 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3052 'A', '\0', ret, dst[0], dst[1], GetLastError());
3054 /* If size is given, result is not NUL terminated */
3055 SetLastError(0);
3056 src[0] = 'A';
3057 src[1] = 'A';
3058 dst[0] = 'X';
3059 dst[1] = 'X';
3060 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3061 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3062 ok(dst[0] == 'A' && dst[1] == 'X',
3063 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3064 'A','X', ret, dst[0], dst[1], GetLastError());
3066 /* MAP_FOLDDIGITS */
3067 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3069 /* Check everything before this range */
3070 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3072 SetLastError(0);
3073 src[0] = ch;
3074 src[1] = dst[0] = '\0';
3075 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3076 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3078 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3079 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3080 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3081 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3082 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3083 "char %04x should not be a digit\n", ch );
3086 if (digitRanges[j] == 0xffff)
3087 break; /* Finished the whole code point space */
3089 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3091 WCHAR c;
3093 /* Map out of sequence characters */
3094 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3095 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3096 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3097 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3098 else c = ch;
3099 SetLastError(0);
3100 src[0] = c;
3101 src[1] = dst[0] = '\0';
3102 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3103 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3105 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3106 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3107 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3108 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3109 strchrW(noDigitAvailable, c),
3110 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3111 ch, '0' + digitRanges[j] - ch, dst[0]);
3113 prev_ch = ch;
3116 /* MAP_FOLDCZONE */
3117 SetLastError(0);
3118 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3119 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3120 "Got %d, error %d\n", ret, GetLastError());
3121 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3122 "MAP_FOLDCZONE: Expanded incorrectly\n");
3124 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3125 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3126 "Got %d, error %d\n", ret, GetLastError());
3127 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3128 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3129 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3131 /* MAP_EXPAND_LIGATURES */
3132 SetLastError(0);
3133 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3134 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3135 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3136 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3137 "Got %d, error %d\n", ret, GetLastError());
3138 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3139 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3142 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3147 #define LCID_OK(l) \
3148 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3149 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3150 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3151 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3152 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3154 static void test_ConvertDefaultLocale(void)
3156 LCID lcid;
3158 /* Doesn't change lcid, even if non default sublang/sort used */
3159 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3160 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3161 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3162 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3164 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3165 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3166 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3167 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3168 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3170 /* Invariant language is not treated specially */
3171 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3173 /* User/system default languages alone are not mapped */
3174 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3175 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3177 /* Default lcids */
3178 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3179 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3180 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3181 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3182 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3183 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3186 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3187 DWORD dwFlags, LONG_PTR lParam)
3189 if (winetest_debug > 1)
3190 trace("%08x, %s, %s, %08x, %08lx\n",
3191 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3193 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3194 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3196 /* If lParam is one, we are calling with flags defaulted from 0 */
3197 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3198 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3200 return TRUE;
3203 static void test_EnumSystemLanguageGroupsA(void)
3205 BOOL ret;
3207 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3209 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3210 return;
3213 /* No enumeration proc */
3214 SetLastError(0);
3215 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3216 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3218 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3219 return;
3221 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3222 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3224 /* Invalid flags */
3225 SetLastError(0);
3226 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3227 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3229 /* No flags - defaults to LGRPID_INSTALLED */
3230 SetLastError(0xdeadbeef);
3231 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3232 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3234 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3235 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3238 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3240 if (winetest_debug > 1)
3241 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3242 return TRUE;
3245 static void test_EnumSystemLocalesEx(void)
3247 BOOL ret;
3249 if (!pEnumSystemLocalesEx)
3251 win_skip( "EnumSystemLocalesEx not available\n" );
3252 return;
3254 SetLastError( 0xdeadbeef );
3255 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3256 ok( !ret, "should have failed\n" );
3257 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3258 SetLastError( 0xdeadbeef );
3259 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3260 ok( ret, "failed err %u\n", GetLastError() );
3263 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3264 LONG_PTR lParam)
3266 if (winetest_debug > 1)
3267 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3269 /* invalid locale enumerated on some platforms */
3270 if (lcid == 0)
3271 return TRUE;
3273 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3274 "Enumerated grp %d not valid\n", lgrpid);
3275 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3276 "Enumerated grp locale %04x not valid\n", lcid);
3277 return TRUE;
3280 static void test_EnumLanguageGroupLocalesA(void)
3282 BOOL ret;
3284 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3286 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3287 return;
3290 /* No enumeration proc */
3291 SetLastError(0);
3292 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3293 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3295 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3296 return;
3298 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3299 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3301 /* lgrpid too small */
3302 SetLastError(0);
3303 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3304 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3305 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3307 /* lgrpid too big */
3308 SetLastError(0);
3309 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3310 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3311 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3313 /* dwFlags is reserved */
3314 SetLastError(0);
3315 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3316 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3317 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3319 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3322 static void test_SetLocaleInfoA(void)
3324 BOOL bRet;
3325 LCID lcid = GetUserDefaultLCID();
3327 /* Null data */
3328 SetLastError(0);
3329 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3330 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3331 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3333 /* IDATE */
3334 SetLastError(0);
3335 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3336 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3337 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3339 /* ILDATE */
3340 SetLastError(0);
3341 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3342 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3343 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3346 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3348 if (winetest_debug > 1)
3349 trace("%s %08lx\n", value, lParam);
3350 return(TRUE);
3353 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3355 ok(!enumCount, "callback called again unexpected\n");
3356 enumCount++;
3357 return(FALSE);
3360 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3362 ok(0,"callback called unexpected\n");
3363 return(FALSE);
3366 static void test_EnumUILanguageA(void)
3368 BOOL ret;
3369 if (!pEnumUILanguagesA) {
3370 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3371 return;
3374 SetLastError(ERROR_SUCCESS);
3375 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3376 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3378 win_skip("EnumUILanguagesA is not implemented\n");
3379 return;
3381 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3383 enumCount = 0;
3384 SetLastError(ERROR_SUCCESS);
3385 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3386 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3388 SetLastError(ERROR_SUCCESS);
3389 ret = pEnumUILanguagesA(NULL, 0, 0);
3390 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3391 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3392 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3394 SetLastError(ERROR_SUCCESS);
3395 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3396 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3397 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3399 SetLastError(ERROR_SUCCESS);
3400 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3401 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3402 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3403 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3406 static char date_fmt_buf[1024];
3407 static WCHAR date_fmt_bufW[1024];
3409 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3411 lstrcatA(date_fmt_buf, fmt);
3412 lstrcatA(date_fmt_buf, "\n");
3413 return TRUE;
3416 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3418 lstrcatW(date_fmt_bufW, fmt);
3419 return FALSE;
3422 static void test_EnumDateFormatsA(void)
3424 char *p, buf[256];
3425 BOOL ret;
3426 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3428 date_fmt_buf[0] = 0;
3429 SetLastError(0xdeadbeef);
3430 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3431 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3433 win_skip("0 for dwFlags is not supported\n");
3435 else
3437 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3438 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3439 /* test the 1st enumerated format */
3440 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3441 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3442 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3443 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3446 date_fmt_buf[0] = 0;
3447 SetLastError(0xdeadbeef);
3448 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3449 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3451 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3453 else
3455 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3456 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3457 /* test the 1st enumerated format */
3458 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3459 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3460 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3461 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3464 date_fmt_buf[0] = 0;
3465 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3466 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3467 trace("EnumDateFormatsA(DATE_SHORTDATE): %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_SSHORTDATE, buf, sizeof(buf));
3471 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) 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 = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3476 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3477 trace("EnumDateFormatsA(DATE_LONGDATE): %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_SLONGDATE, buf, sizeof(buf));
3481 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3482 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3484 date_fmt_buf[0] = 0;
3485 SetLastError(0xdeadbeef);
3486 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3487 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3489 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3490 return;
3492 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3493 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3494 /* test the 1st enumerated format */
3495 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3496 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3497 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3498 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3499 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3502 static void test_EnumTimeFormatsA(void)
3504 char *p, buf[256];
3505 BOOL ret;
3506 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3508 date_fmt_buf[0] = 0;
3509 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3510 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3511 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3512 /* test the 1st enumerated format */
3513 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3514 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3515 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3516 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3518 date_fmt_buf[0] = 0;
3519 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3520 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3521 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3522 /* test the 1st enumerated format */
3523 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3524 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3525 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3526 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3529 static void test_EnumTimeFormatsW(void)
3531 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3532 WCHAR bufW[256];
3533 BOOL ret;
3535 date_fmt_bufW[0] = 0;
3536 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3537 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3538 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3539 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3540 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3541 wine_dbgstr_w(bufW));
3543 date_fmt_bufW[0] = 0;
3544 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3545 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3546 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3547 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3548 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3549 wine_dbgstr_w(bufW));
3551 /* TIME_NOSECONDS is Win7+ feature */
3552 date_fmt_bufW[0] = 0;
3553 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3554 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3555 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3556 else {
3557 char buf[256];
3559 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3560 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3561 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3562 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3563 wine_dbgstr_w(bufW));
3565 /* EnumTimeFormatsA doesn't support this flag */
3566 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3567 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3568 GetLastError());
3570 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3571 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3572 GetLastError());
3574 /* And it's not supported by GetLocaleInfoA either */
3575 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3576 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3577 GetLastError());
3580 static void test_GetCPInfo(void)
3582 BOOL ret;
3583 CPINFO cpinfo;
3585 SetLastError(0xdeadbeef);
3586 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3587 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3588 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3589 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3591 SetLastError(0xdeadbeef);
3592 ret = GetCPInfo(CP_UTF7, &cpinfo);
3593 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3595 win_skip("Codepage CP_UTF7 is not installed/available\n");
3597 else
3599 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3600 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3601 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3602 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3603 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3604 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3607 SetLastError(0xdeadbeef);
3608 ret = GetCPInfo(CP_UTF8, &cpinfo);
3609 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3611 win_skip("Codepage CP_UTF8 is not installed/available\n");
3613 else
3615 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3616 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3617 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3618 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3619 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3620 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3621 "expected 4, got %u\n", cpinfo.MaxCharSize);
3626 * The CT_TYPE1 has varied over windows version.
3627 * The current target for correct behavior is windows 7.
3628 * There was a big shift between windows 2000 (first introduced) and windows Xp
3629 * Most of the old values below are from windows 2000.
3630 * A smaller subset of changes happened between windows Xp and Window vista/7
3632 static void test_GetStringTypeW(void)
3634 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3635 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3636 C1_SPACE | C1_BLANK | C1_DEFINED,
3637 C1_SPACE | C1_BLANK | C1_DEFINED,
3638 C1_SPACE | C1_BLANK | C1_DEFINED,
3639 C1_CNTRL | C1_BLANK | C1_DEFINED};
3640 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3641 C1_SPACE | C1_BLANK,
3642 C1_SPACE | C1_BLANK,
3643 C1_SPACE | C1_BLANK,
3644 C1_SPACE | C1_BLANK};
3646 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3648 /* Lu, Ll, Lt */
3649 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3650 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3651 C1_LOWER | C1_ALPHA,
3652 C1_UPPER | C1_LOWER | C1_ALPHA,
3653 C1_ALPHA};
3655 /* Sk, Sk, Mn, So, Me */
3656 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3657 /* Sc, Sm, No,*/
3658 0xffe0, 0xffe9, 0x2153};
3660 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3661 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3662 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3663 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3664 C1_ALPHA | C1_DEFINED,
3665 C1_CNTRL | C1_DEFINED,
3666 C1_PUNCT | C1_DEFINED,
3667 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3668 C1_ALPHA | C1_LOWER | C1_DEFINED,
3669 C1_ALPHA | C1_DEFINED };
3670 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3671 C1_ALPHA | C1_DEFINED,
3672 C1_CNTRL | C1_DEFINED,
3673 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3674 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3675 C1_ALPHA | C1_DEFINED,
3676 C1_DEFINED
3678 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3679 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3681 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3682 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3683 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3684 static const WCHAR lower_special[] = {0x2071, 0x207f};
3685 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3686 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3687 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3688 0xfff9, 0xfffa, 0xfffb};
3689 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3691 WORD types[20];
3692 BOOL ret;
3693 WCHAR ch;
3694 int i;
3696 /* NULL src */
3697 SetLastError(0xdeadbeef);
3698 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3699 ok(!ret, "got %d\n", ret);
3700 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3702 SetLastError(0xdeadbeef);
3703 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3704 ok(!ret, "got %d\n", ret);
3705 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3707 SetLastError(0xdeadbeef);
3708 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3709 ok(!ret, "got %d\n", ret);
3710 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3712 memset(types,0,sizeof(types));
3713 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3714 for (i = 0; i < 5; i++)
3715 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]);
3717 memset(types,0,sizeof(types));
3718 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3719 for (i = 0; i < 3; i++)
3720 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]));
3721 memset(types,0,sizeof(types));
3722 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3723 for (i = 0; i < 5; i++)
3724 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3726 memset(types,0,sizeof(types));
3727 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3728 for (i = 0; i < 8; i++)
3729 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);
3731 memset(types,0,sizeof(types));
3732 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3733 for (i = 0; i < 7; i++)
3734 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]);
3736 memset(types,0,sizeof(types));
3737 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3738 for (i = 0; i < 7; i++)
3739 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));
3742 memset(types,0,sizeof(types));
3743 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3744 for (i = 0; i < 12; i++)
3745 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);
3747 memset(types,0,sizeof(types));
3748 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3749 for (i = 0; i < 3; i++)
3750 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);
3752 memset(types,0,sizeof(types));
3753 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3754 for (i = 0; i < 2; i++)
3755 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);
3757 memset(types,0,sizeof(types));
3758 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3759 for (i = 0; i < 20; i++)
3760 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);
3762 memset(types,0,sizeof(types));
3763 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3764 for (i = 0; i < 3; i++)
3765 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 );
3767 /* surrogate pairs */
3768 ch = 0xd800;
3769 memset(types, 0, sizeof(types));
3770 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3771 if (types[0] == C3_NOTAPPLICABLE)
3772 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
3773 else {
3774 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
3776 ch = 0xdc00;
3777 memset(types, 0, sizeof(types));
3778 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3779 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
3783 static void test_IdnToNameprepUnicode(void)
3785 struct {
3786 DWORD in_len;
3787 const WCHAR in[64];
3788 DWORD ret;
3789 DWORD broken_ret;
3790 const WCHAR out[64];
3791 DWORD flags;
3792 DWORD err;
3793 DWORD todo;
3794 } test_data[] = {
3796 5, {'t','e','s','t',0},
3797 5, 5, {'t','e','s','t',0},
3798 0, 0xdeadbeef
3801 3, {'a',0xe111,'b'},
3802 0, 0, {0},
3803 0, ERROR_INVALID_NAME
3806 4, {'t',0,'e',0},
3807 0, 0, {0},
3808 0, ERROR_INVALID_NAME
3811 1, {'T',0},
3812 1, 1, {'T',0},
3813 0, 0xdeadbeef
3816 1, {0},
3817 0, 0, {0},
3818 0, ERROR_INVALID_NAME
3821 6, {' ','-','/','[',']',0},
3822 6, 6, {' ','-','/','[',']',0},
3823 0, 0xdeadbeef
3826 3, {'a','-','a'},
3827 3, 3, {'a','-','a'},
3828 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3831 3, {'a','a','-'},
3832 0, 0, {0},
3833 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3835 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3836 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3837 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3838 0, 0xdeadbeef, TRUE
3841 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3842 2, 0, {'t',0},
3843 0, 0xdeadbeef
3845 { /* Another example of incorrectly working FoldString (composition) */
3846 2, {0x3b0, 0},
3847 2, 2, {0x3b0, 0},
3848 0, 0xdeadbeef, TRUE
3851 2, {0x221, 0},
3852 0, 2, {0},
3853 0, ERROR_NO_UNICODE_TRANSLATION
3856 2, {0x221, 0},
3857 2, 2, {0x221, 0},
3858 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3861 5, {'a','.','.','a',0},
3862 0, 0, {0},
3863 0, ERROR_INVALID_NAME
3866 3, {'a','.',0},
3867 3, 3, {'a','.',0},
3868 0, 0xdeadbeef
3872 WCHAR buf[1024];
3873 DWORD i, ret, err;
3875 if (!pIdnToNameprepUnicode)
3877 win_skip("IdnToNameprepUnicode is not available\n");
3878 return;
3881 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3882 test_data[0].in_len, NULL, 0);
3883 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3885 SetLastError(0xdeadbeef);
3886 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3887 test_data[1].in_len, NULL, 0);
3888 err = GetLastError();
3889 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3890 ok(err == test_data[1].err, "err = %d\n", err);
3892 SetLastError(0xdeadbeef);
3893 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3894 buf, sizeof(buf)/sizeof(WCHAR));
3895 err = GetLastError();
3896 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3897 ok(err == 0xdeadbeef, "err = %d\n", err);
3899 SetLastError(0xdeadbeef);
3900 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3901 buf, sizeof(buf)/sizeof(WCHAR));
3902 err = GetLastError();
3903 ok(ret == 0, "ret = %d\n", ret);
3904 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3906 SetLastError(0xdeadbeef);
3907 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3908 buf, sizeof(buf)/sizeof(WCHAR));
3909 err = GetLastError();
3910 ok(ret == 0, "ret = %d\n", ret);
3911 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3913 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3914 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3915 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3917 SetLastError(0xdeadbeef);
3918 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3919 err = GetLastError();
3920 ok(ret == 0, "ret = %d\n", ret);
3921 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3923 SetLastError(0xdeadbeef);
3924 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3925 err = GetLastError();
3926 ok(ret == 0, "ret = %d\n", ret);
3927 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
3928 "err = %d\n", err);
3930 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3932 SetLastError(0xdeadbeef);
3933 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3934 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3935 err = GetLastError();
3937 if (!test_data[i].todo)
3939 ok(ret == test_data[i].ret ||
3940 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3942 else
3944 todo_wine ok(ret == test_data[i].ret ||
3945 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3947 if(ret != test_data[i].ret)
3948 continue;
3950 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3951 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3952 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3956 static void test_IdnToAscii(void)
3958 struct {
3959 DWORD in_len;
3960 const WCHAR in[64];
3961 DWORD ret;
3962 const WCHAR out[64];
3963 DWORD flags;
3964 DWORD err;
3965 } test_data[] = {
3967 5, {'T','e','s','t',0},
3968 5, {'T','e','s','t',0},
3969 0, 0xdeadbeef
3972 5, {'T','e',0x017c,'s','t',0},
3973 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3974 0, 0xdeadbeef
3977 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3978 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3979 0, 0xdeadbeef
3982 3, {0x0105,'.',0},
3983 9, {'x','n','-','-','2','d','a','.',0},
3984 0, 0xdeadbeef
3987 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3988 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3989 0, 0xdeadbeef
3992 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3993 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3994 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3995 0, 0xdeadbeef
3998 2, {0x221,0},
3999 8, {'x','n','-','-','6','l','a',0},
4000 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4004 WCHAR buf[1024];
4005 DWORD i, ret, err;
4007 if (!pIdnToAscii)
4009 win_skip("IdnToAscii is not available\n");
4010 return;
4013 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4015 SetLastError(0xdeadbeef);
4016 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4017 test_data[i].in_len, buf, sizeof(buf));
4018 err = GetLastError();
4019 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4020 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4021 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4022 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4026 static void test_IdnToUnicode(void)
4028 struct {
4029 DWORD in_len;
4030 const WCHAR in[64];
4031 DWORD ret;
4032 const WCHAR out[64];
4033 DWORD flags;
4034 DWORD err;
4035 } test_data[] = {
4037 5, {'T','e','s','.',0},
4038 5, {'T','e','s','.',0},
4039 0, 0xdeadbeef
4042 2, {0x105,0},
4043 0, {0},
4044 0, ERROR_INVALID_NAME
4047 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4048 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4049 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4050 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4051 0x05d1,0x05e8,0x05d9,0x05ea,0},
4052 0, 0xdeadbeef
4055 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4056 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4057 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4058 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4059 0, 0xdeadbeef
4062 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4063 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4064 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4065 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4066 0, {0},
4067 0, ERROR_INVALID_NAME
4070 8, {'x','n','-','-','6','l','a',0},
4071 2, {0x221,0},
4072 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4076 WCHAR buf[1024];
4077 DWORD i, ret, err;
4079 if (!pIdnToUnicode)
4081 win_skip("IdnToUnicode is not available\n");
4082 return;
4085 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4087 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4088 test_data[i].in_len, NULL, 0);
4089 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4091 SetLastError(0xdeadbeef);
4092 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4093 test_data[i].in_len, buf, sizeof(buf));
4094 err = GetLastError();
4095 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4096 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4097 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4098 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4102 static void test_GetLocaleInfoEx(void)
4104 static const WCHAR enW[] = {'e','n',0};
4105 WCHAR bufferW[80];
4106 INT ret;
4108 if (!pGetLocaleInfoEx)
4110 win_skip("GetLocaleInfoEx not supported\n");
4111 return;
4114 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4115 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4116 if (ret)
4118 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4119 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4120 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4121 static const WCHAR usaW[] = {'U','S','A',0};
4122 static const WCHAR enuW[] = {'E','N','U',0};
4123 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4124 DWORD val;
4126 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4127 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4129 SetLastError(0xdeadbeef);
4130 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4131 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4133 SetLastError(0xdeadbeef);
4134 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4135 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4137 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4138 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4139 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4141 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4142 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4143 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4145 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4146 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4147 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4149 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4150 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4151 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4152 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4154 skip("Non-English locale\n");
4156 else
4157 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4159 bufferW[0] = 0;
4160 SetLastError(0xdeadbeef);
4161 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4162 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4164 while (*ptr->name)
4166 val = 0;
4167 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4168 if (ptr->todo)
4169 todo_wine
4170 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4171 else
4172 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4173 bufferW[0] = 0;
4174 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4175 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4176 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4177 ptr++;
4182 static void test_IsValidLocaleName(void)
4184 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4185 static const WCHAR zzW[] = {'z','z',0};
4186 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4187 BOOL ret;
4189 if (!pIsValidLocaleName)
4191 win_skip("IsValidLocaleName not supported\n");
4192 return;
4195 ret = pIsValidLocaleName(enusW);
4196 ok(ret, "IsValidLocaleName failed\n");
4197 ret = pIsValidLocaleName(zzW);
4198 ok(!ret, "IsValidLocaleName should have failed\n");
4199 ret = pIsValidLocaleName(zzzzW);
4200 ok(!ret, "IsValidLocaleName should have failed\n");
4201 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4202 ok(ret, "IsValidLocaleName failed\n");
4205 static void test_CompareStringOrdinal(void)
4207 INT ret;
4208 WCHAR test1[] = { 't','e','s','t',0 };
4209 WCHAR test2[] = { 'T','e','S','t',0 };
4210 WCHAR test3[] = { 't','e','s','t','3',0 };
4211 WCHAR null1[] = { 'a',0,'a',0 };
4212 WCHAR null2[] = { 'a',0,'b',0 };
4213 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4214 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4215 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4216 WCHAR coop2[] = { 'c','o','o','p',0 };
4217 WCHAR nonascii1[] = { 0x0102,0 };
4218 WCHAR nonascii2[] = { 0x0201,0 };
4220 if (!pCompareStringOrdinal)
4222 win_skip("CompareStringOrdinal not supported\n");
4223 return;
4226 /* Check errors */
4227 SetLastError(0xdeadbeef);
4228 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4229 ok(!ret, "Got %u, expected 0\n", ret);
4230 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4231 SetLastError(0xdeadbeef);
4232 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4233 ok(!ret, "Got %u, expected 0\n", ret);
4234 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4235 SetLastError(0xdeadbeef);
4236 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4237 ok(!ret, "Got %u, expected 0\n", ret);
4238 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4240 /* Check case */
4241 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4242 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4243 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4244 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4245 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4246 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4247 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4248 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4250 /* Check different sizes */
4251 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4252 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4253 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4254 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4256 /* Check null character */
4257 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4258 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4259 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4260 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4261 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4262 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4263 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4264 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4266 /* Check ordinal behaviour */
4267 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4268 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4269 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4270 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4271 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4272 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4273 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4274 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4277 static void test_GetGeoInfo(void)
4279 char buffA[20];
4280 INT ret;
4282 if (!pGetGeoInfoA)
4284 win_skip("GetGeoInfo is not available.\n");
4285 return;
4288 /* unassigned id */
4289 SetLastError(0xdeadbeef);
4290 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4291 ok(ret == 0, "got %d\n", ret);
4292 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4294 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4295 ok(ret == 3, "got %d\n", ret);
4297 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4298 ok(ret == 4, "got %d\n", ret);
4300 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4301 ok(ret == 3, "got %d\n", ret);
4302 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4304 /* buffer pointer not NULL, length is 0 - return required length */
4305 buffA[0] = 'a';
4306 SetLastError(0xdeadbeef);
4307 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4308 ok(ret == 3, "got %d\n", ret);
4309 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4311 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4312 ok(ret == 4, "got %d\n", ret);
4313 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4315 /* shorter buffer */
4316 SetLastError(0xdeadbeef);
4317 buffA[1] = buffA[2] = 0;
4318 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4319 ok(ret == 0, "got %d\n", ret);
4320 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4321 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4323 /* GEO_NATION returns GEOID in a string form */
4324 buffA[0] = 0;
4325 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4326 ok(ret == 4, "got %d\n", ret);
4327 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4329 /* GEO_PARENT */
4330 buffA[0] = 0;
4331 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4332 if (ret == 0)
4333 win_skip("GEO_PARENT not supported.\n");
4334 else
4336 ok(ret == 6, "got %d\n", ret);
4337 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4340 buffA[0] = 0;
4341 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4342 if (ret == 0)
4343 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4344 else
4346 ok(ret == 4, "got %d\n", ret);
4347 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4350 /* try invalid type value */
4351 SetLastError(0xdeadbeef);
4352 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4353 ok(ret == 0, "got %d\n", ret);
4354 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4357 static int geoidenum_count;
4358 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4360 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4361 ok(ret == 3, "got %d for %d\n", ret, geoid);
4362 /* valid geoid starts at 2 */
4363 ok(geoid >= 2, "got geoid %d\n", geoid);
4365 return geoidenum_count++ < 5;
4368 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4370 geoidenum_count++;
4371 return TRUE;
4374 static void test_EnumSystemGeoID(void)
4376 BOOL ret;
4378 if (!pEnumSystemGeoID)
4380 win_skip("EnumSystemGeoID is not available.\n");
4381 return;
4384 SetLastError(0xdeadbeef);
4385 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4386 ok(!ret, "got %d\n", ret);
4387 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4389 SetLastError(0xdeadbeef);
4390 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4391 ok(!ret, "got %d\n", ret);
4392 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4394 SetLastError(0xdeadbeef);
4395 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4396 ok(!ret, "got %d\n", ret);
4397 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4399 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4400 ok(ret, "got %d\n", ret);
4402 /* only the first level is enumerated, not the whole hierarchy */
4403 geoidenum_count = 0;
4404 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4405 if (ret == 0)
4406 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4407 else
4408 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4410 geoidenum_count = 0;
4411 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4412 if (ret == 0)
4413 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4414 else
4416 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4418 geoidenum_count = 0;
4419 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4420 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4424 struct invariant_entry {
4425 const char *name;
4426 int id;
4427 const char *expect;
4430 #define X(x) #x, x
4431 static const struct invariant_entry invariant_list[] = {
4432 { X(LOCALE_ILANGUAGE), "007f" },
4433 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4434 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4435 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4436 { X(LOCALE_ICOUNTRY), "1" },
4437 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4438 { X(LOCALE_SABBREVCTRYNAME), "IVC" },
4439 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4440 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4441 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4442 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4443 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4444 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4445 { X(LOCALE_SLIST), "," },
4446 { X(LOCALE_IMEASURE), "0" },
4447 { X(LOCALE_SDECIMAL), "." },
4448 { X(LOCALE_STHOUSAND), "," },
4449 { X(LOCALE_SGROUPING), "3;0" },
4450 { X(LOCALE_IDIGITS), "2" },
4451 { X(LOCALE_ILZERO), "1" },
4452 { X(LOCALE_INEGNUMBER), "1" },
4453 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4454 { X(LOCALE_SCURRENCY), "\x00a4" },
4455 { X(LOCALE_SINTLSYMBOL), "XDR" },
4456 { X(LOCALE_SMONDECIMALSEP), "." },
4457 { X(LOCALE_SMONTHOUSANDSEP), "," },
4458 { X(LOCALE_SMONGROUPING), "3;0" },
4459 { X(LOCALE_ICURRDIGITS), "2" },
4460 { X(LOCALE_IINTLCURRDIGITS), "2" },
4461 { X(LOCALE_ICURRENCY), "0" },
4462 { X(LOCALE_INEGCURR), "0" },
4463 { X(LOCALE_SDATE), "/" },
4464 { X(LOCALE_STIME), ":" },
4465 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4466 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4467 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4468 { X(LOCALE_IDATE), "0" },
4469 { X(LOCALE_ILDATE), "1" },
4470 { X(LOCALE_ITIME), "1" },
4471 { X(LOCALE_ITIMEMARKPOSN), "0" },
4472 { X(LOCALE_ICENTURY), "1" },
4473 { X(LOCALE_ITLZERO), "1" },
4474 { X(LOCALE_IDAYLZERO), "1" },
4475 { X(LOCALE_IMONLZERO), "1" },
4476 { X(LOCALE_S1159), "AM" },
4477 { X(LOCALE_S2359), "PM" },
4478 { X(LOCALE_ICALENDARTYPE), "1" },
4479 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4480 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4481 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4482 { X(LOCALE_SDAYNAME1), "Monday" },
4483 { X(LOCALE_SDAYNAME2), "Tuesday" },
4484 { X(LOCALE_SDAYNAME3), "Wednesday" },
4485 { X(LOCALE_SDAYNAME4), "Thursday" },
4486 { X(LOCALE_SDAYNAME5), "Friday" },
4487 { X(LOCALE_SDAYNAME6), "Saturday" },
4488 { X(LOCALE_SDAYNAME7), "Sunday" },
4489 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4490 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4491 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4492 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4493 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4494 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4495 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4496 { X(LOCALE_SMONTHNAME1), "January" },
4497 { X(LOCALE_SMONTHNAME2), "February" },
4498 { X(LOCALE_SMONTHNAME3), "March" },
4499 { X(LOCALE_SMONTHNAME4), "April" },
4500 { X(LOCALE_SMONTHNAME5), "May" },
4501 { X(LOCALE_SMONTHNAME6), "June" },
4502 { X(LOCALE_SMONTHNAME7), "July" },
4503 { X(LOCALE_SMONTHNAME8), "August" },
4504 { X(LOCALE_SMONTHNAME9), "September" },
4505 { X(LOCALE_SMONTHNAME10), "October" },
4506 { X(LOCALE_SMONTHNAME11), "November" },
4507 { X(LOCALE_SMONTHNAME12), "December" },
4508 { X(LOCALE_SMONTHNAME13), "" },
4509 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4510 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4511 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4512 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4513 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4514 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4515 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4516 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4517 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4518 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4519 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4520 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4521 { X(LOCALE_SABBREVMONTHNAME13), "" },
4522 { X(LOCALE_SPOSITIVESIGN), "+" },
4523 { X(LOCALE_SNEGATIVESIGN), "-" },
4524 { X(LOCALE_IPOSSIGNPOSN), "3" },
4525 { X(LOCALE_INEGSIGNPOSN), "0" },
4526 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4527 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4528 { X(LOCALE_INEGSYMPRECEDES), "1" },
4529 { X(LOCALE_INEGSEPBYSPACE), "0" },
4530 { X(LOCALE_SISO639LANGNAME), "iv" },
4531 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4532 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4533 { X(LOCALE_IPAPERSIZE), "9" },
4534 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4535 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4536 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4537 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4538 { X(LOCALE_SNAME), "" },
4539 { X(LOCALE_SSCRIPTS), "Latn;" },
4540 { 0 }
4542 #undef X
4544 static void test_invariant(void)
4546 int ret;
4547 int len;
4548 char buffer[BUFFER_SIZE];
4549 const struct invariant_entry *ptr = invariant_list;
4551 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4553 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4554 return;
4557 while (ptr->name)
4559 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4560 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4561 win_skip("not supported\n"); /* winxp/win2k3 */
4562 else
4564 len = strlen(ptr->expect)+1; /* include \0 */
4565 ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
4566 ptr->id, len, ret, GetLastError());
4567 ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
4568 ptr->id, ptr->expect, buffer);
4571 ptr++;
4574 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4575 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4577 skip("Non-English locale\n");
4579 else
4581 /* some locales translate these */
4582 static const char lang[] = "Invariant Language (Invariant Country)";
4583 static const char cntry[] = "Invariant Country";
4584 static const char sortm[] = "Math Alphanumerics";
4585 static const char sortd[] = "Default"; /* win2k3 */
4587 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4588 len = lstrlenA(lang) + 1;
4589 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4590 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4592 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4593 len = lstrlenA(cntry) + 1;
4594 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4595 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4597 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4598 if (ret == lstrlenA(sortm)+1)
4599 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4600 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4601 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4602 else
4603 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4604 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4608 static void test_GetSystemPreferredUILanguages(void)
4610 BOOL ret;
4611 ULONG count, size, size_id, size_name, size_buffer;
4612 WCHAR *buffer;
4615 if (!pGetSystemPreferredUILanguages)
4617 win_skip("GetSystemPreferredUILanguages is not available.\n");
4618 return;
4621 /* (in)valid first parameter */
4622 count = 0xdeadbeef;
4623 size = 0;
4624 SetLastError(0xdeadbeef);
4625 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4626 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4627 ok(count, "Expected count > 0\n");
4628 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4630 count = 0xdeadbeef;
4631 size = 0;
4632 SetLastError(0xdeadbeef);
4633 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4634 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4635 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4636 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4638 count = 0xdeadbeef;
4639 size = 0;
4640 SetLastError(0xdeadbeef);
4641 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &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 count = 0xdeadbeef;
4647 size = 0;
4648 SetLastError(0xdeadbeef);
4649 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
4650 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4651 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4652 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4654 count = 0xdeadbeef;
4655 size = 0;
4656 SetLastError(0xdeadbeef);
4657 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4658 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4659 ok(count, "Expected count > 0\n");
4660 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4662 count = 0xdeadbeef;
4663 size = 0;
4664 SetLastError(0xdeadbeef);
4665 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4666 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4667 ok(count, "Expected count > 0\n");
4668 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4670 /* second parameter
4671 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
4672 * -> unhandled exception c0000005
4675 /* invalid third parameter */
4676 count = 0xdeadbeef;
4677 size = 1;
4678 SetLastError(0xdeadbeef);
4679 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
4680 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4681 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4682 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4684 /* fourth parameter
4685 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
4686 * -> unhandled exception c0000005
4689 count = 0xdeadbeef;
4690 size_id = 0;
4691 SetLastError(0xdeadbeef);
4692 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
4693 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4694 ok(count, "Expected count > 0\n");
4695 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
4697 count = 0xdeadbeef;
4698 size_name = 0;
4699 SetLastError(0xdeadbeef);
4700 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
4701 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4702 ok(count, "Expected count > 0\n");
4703 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
4705 size_buffer = max(size_id, size_name);
4706 if(!size_buffer)
4708 skip("No vaild buffer size\n");
4709 return;
4712 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
4713 if (!buffer)
4715 skip("Failed to allocate memory for %d chars\n", size_buffer);
4716 return;
4719 count = 0xdeadbeef;
4720 size = size_buffer;
4721 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4722 SetLastError(0xdeadbeef);
4723 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4724 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4725 ok(count, "Expected count > 0\n");
4726 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4727 if (ret && size % 6 == 1)
4728 ok(!buffer[size -2] && !buffer[size -1],
4729 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4730 buffer[size -2], buffer[size -1]);
4732 count = 0xdeadbeef;
4733 size = size_buffer;
4734 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4735 SetLastError(0xdeadbeef);
4736 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4737 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4738 ok(count, "Expected count > 0\n");
4739 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4740 if (ret && size % 5 == 1)
4741 ok(!buffer[size -2] && !buffer[size -1],
4742 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4743 buffer[size -2], buffer[size -1]);
4745 count = 0xdeadbeef;
4746 size = size_buffer;
4747 SetLastError(0xdeadbeef);
4748 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
4749 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4750 ok(count, "Expected count > 0\n");
4751 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4752 if (ret && size % 5 == 1)
4753 ok(!buffer[size -2] && !buffer[size -1],
4754 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4755 buffer[size -2], buffer[size -1]);
4757 count = 0xdeadbeef;
4758 size = 0;
4759 SetLastError(0xdeadbeef);
4760 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4761 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4762 ok(count, "Expected count > 0\n");
4763 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4764 if (ret && size % 6 == 1)
4765 ok(!buffer[size -2] && !buffer[size -1],
4766 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4767 buffer[size -2], buffer[size -1]);
4769 count = 0xdeadbeef;
4770 size = 1;
4771 SetLastError(0xdeadbeef);
4772 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4773 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4774 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4775 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4777 count = 0xdeadbeef;
4778 size = size_id -1;
4779 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4780 SetLastError(0xdeadbeef);
4781 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4782 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4783 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4784 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4786 count = 0xdeadbeef;
4787 size = size_id -2;
4788 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4789 SetLastError(0xdeadbeef);
4790 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4791 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4792 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4793 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4796 START_TEST(locale)
4798 InitFunctionPointers();
4800 test_EnumTimeFormatsA();
4801 test_EnumTimeFormatsW();
4802 test_EnumDateFormatsA();
4803 test_GetLocaleInfoA();
4804 test_GetLocaleInfoW();
4805 test_GetLocaleInfoEx();
4806 test_GetTimeFormatA();
4807 test_GetTimeFormatEx();
4808 test_GetDateFormatA();
4809 test_GetDateFormatEx();
4810 test_GetDateFormatW();
4811 test_GetCurrencyFormatA(); /* Also tests the W version */
4812 test_GetNumberFormatA(); /* Also tests the W version */
4813 test_CompareStringA();
4814 test_CompareStringW();
4815 test_CompareStringEx();
4816 test_LCMapStringA();
4817 test_LCMapStringW();
4818 test_LCMapStringEx();
4819 test_LocaleNameToLCID();
4820 test_FoldStringA();
4821 test_FoldStringW();
4822 test_ConvertDefaultLocale();
4823 test_EnumSystemLanguageGroupsA();
4824 test_EnumSystemLocalesEx();
4825 test_EnumLanguageGroupLocalesA();
4826 test_SetLocaleInfoA();
4827 test_EnumUILanguageA();
4828 test_GetCPInfo();
4829 test_GetStringTypeW();
4830 test_IdnToNameprepUnicode();
4831 test_IdnToAscii();
4832 test_IdnToUnicode();
4833 test_IsValidLocaleName();
4834 test_CompareStringOrdinal();
4835 test_GetGeoInfo();
4836 test_EnumSystemGeoID();
4837 test_invariant();
4838 test_GetSystemPreferredUILanguages();
4839 /* this requires collation table patch to make it MS compatible */
4840 if (0) test_sorting();