kernel32/tests: Additional test for GetStringTypeW() and Zl/Zp categories.
[wine.git] / dlls / kernel32 / tests / locale.c
blob57dc418d7e7bef7334316d968378f1df29927779
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 todo_wine_if (ptr->todo & 0x1)
333 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
334 wine_dbgstr_w(ptr->name), val, ptr->lcid);
336 /* now check LOCALE_SNAME */
337 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
338 todo_wine_if (ptr->todo & 0x2)
339 ok(!lstrcmpW(bufferW, ptr->sname) ||
340 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
341 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
342 ptr++;
345 else
346 win_skip("English neutral locale not supported\n");
348 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
349 if (!ret) {
350 win_skip("LANG_RUSSIAN locale data unavailable\n");
351 return;
353 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
354 bufferW, COUNTOF(bufferW));
355 if (!ret) {
356 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
357 return;
360 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
361 bufferA[0] = 'a';
362 SetLastError(0xdeadbeef);
363 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
364 bufferA, COUNTOF(bufferA));
365 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
366 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
367 ok(GetLastError() == ERROR_INVALID_FLAGS,
368 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
370 bufferW[0] = 'a';
371 SetLastError(0xdeadbeef);
372 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
373 bufferW, COUNTOF(bufferW));
374 ok(ret == 0,
375 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
376 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
377 ok(GetLastError() == ERROR_INVALID_FLAGS,
378 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
380 /* yes, test empty 13 month entry too */
381 for (i = 0; i < 12; i++) {
382 bufferW[0] = 0;
383 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
384 bufferW, COUNTOF(bufferW));
385 ok(ret, "Expected non zero result\n");
386 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
387 ret, lstrlenW(bufferW));
388 buffer2W[0] = 0;
389 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
390 buffer2W, COUNTOF(buffer2W));
391 ok(ret, "Expected non zero result\n");
392 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
393 ret, lstrlenW(buffer2W));
395 ok(lstrcmpW(bufferW, buffer2W) != 0,
396 "Expected genitive name to differ, got the same for month %d\n", i+1);
398 /* for locale without genitive names nominative returned in both cases */
399 bufferW[0] = 0;
400 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
401 bufferW, COUNTOF(bufferW));
402 ok(ret, "Expected non zero result\n");
403 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
404 ret, lstrlenW(bufferW));
405 buffer2W[0] = 0;
406 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
407 buffer2W, COUNTOF(buffer2W));
408 ok(ret, "Expected non zero result\n");
409 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
410 ret, lstrlenW(buffer2W));
412 ok(lstrcmpW(bufferW, buffer2W) == 0,
413 "Expected same names, got different for month %d\n", i+1);
417 static void test_GetTimeFormatA(void)
419 int ret;
420 SYSTEMTIME curtime;
421 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
422 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
424 memset(&curtime, 2, sizeof(SYSTEMTIME));
425 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
426 SetLastError(0xdeadbeef);
427 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
428 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
429 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
431 curtime.wHour = 8;
432 curtime.wMinute = 56;
433 curtime.wSecond = 13;
434 curtime.wMilliseconds = 22;
435 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
436 SetLastError(0xdeadbeef);
437 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
438 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
439 EXPECT_LENA; EXPECT_EQA;
441 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
442 SetLastError(0xdeadbeef);
443 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
444 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
445 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
447 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
448 SetLastError(0xdeadbeef);
449 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
450 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
451 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
453 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
454 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
455 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
456 EXPECT_LENA;
458 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
459 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
460 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
461 EXPECT_LENA; EXPECT_EQA;
463 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
464 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
465 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
466 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
467 "Expected '', got '%s'\n", buffer );
469 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
470 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &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("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
475 strcpy(Expected, "8:56 AM");
476 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
477 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
478 EXPECT_LENA; EXPECT_EQA;
480 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
481 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
484 "Expected '8.@:56AM', got '%s'\n", buffer );
486 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
487 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
488 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
489 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
490 "Expected '', got '%s'\n", buffer );
492 STRINGSA("t/tt", "A/AM"); /* AM time marker */
493 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
494 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
495 EXPECT_LENA; EXPECT_EQA;
497 curtime.wHour = 13;
498 STRINGSA("t/tt", "P/PM"); /* PM time marker */
499 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
500 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
501 EXPECT_LENA; EXPECT_EQA;
503 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
504 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
505 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
506 EXPECT_LENA; EXPECT_EQA;
508 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
509 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
510 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
511 EXPECT_LENA; EXPECT_EQA;
513 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
514 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
515 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
516 EXPECT_LENA; EXPECT_EQA;
518 curtime.wHour = 14; /* change this to 14 or 2pm */
519 curtime.wMinute = 5;
520 curtime.wSecond = 3;
521 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 */
522 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
523 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
524 EXPECT_LENA; EXPECT_EQA;
526 curtime.wHour = 0;
527 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
528 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
529 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
530 EXPECT_LENA; EXPECT_EQA;
532 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
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 /* try to convert formatting strings with more than two letters
538 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
539 * NOTE: We expect any letter for which there is an upper case value
540 * we should see a replacement. For letters that DO NOT have
541 * upper case values we should see NO REPLACEMENT.
543 curtime.wHour = 8;
544 curtime.wMinute = 56;
545 curtime.wSecond = 13;
546 curtime.wMilliseconds = 22;
547 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
548 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
549 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
550 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
551 EXPECT_LENA; EXPECT_EQA;
553 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
554 strcpy(buffer, "text");
555 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
556 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
557 EXPECT_EQA;
559 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
560 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
561 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
562 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
563 EXPECT_LENA; EXPECT_EQA;
565 STRINGSA("'''", "'"); /* invalid quoted string */
566 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
567 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
568 EXPECT_LENA; EXPECT_EQA;
570 /* test that msdn suggested single quotation usage works as expected */
571 STRINGSA("''''", "'"); /* single quote mark */
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("''HHHHHH", "08"); /* Normal use */
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 /* and test for normal use of the single quotation mark */
582 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
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", "'HHHHHH"); /* Odd 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 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
593 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
595 EXPECT_LENA; EXPECT_EQA;
597 curtime.wHour = 25;
598 STRINGSA("'123'tt", ""); /* Invalid time */
599 SetLastError(0xdeadbeef);
600 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
601 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
602 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
604 curtime.wHour = 12;
605 curtime.wMonth = 60; /* Invalid */
606 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
607 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
608 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
609 EXPECT_LENA; EXPECT_EQA;
612 static void test_GetTimeFormatEx(void)
614 int ret;
615 SYSTEMTIME curtime;
616 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
618 if (!pGetTimeFormatEx)
620 win_skip("GetTimeFormatEx not supported\n");
621 return;
624 memset(&curtime, 2, sizeof(SYSTEMTIME));
625 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
626 SetLastError(0xdeadbeef);
627 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
628 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
629 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
631 curtime.wHour = 8;
632 curtime.wMinute = 56;
633 curtime.wSecond = 13;
634 curtime.wMilliseconds = 22;
635 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
636 SetLastError(0xdeadbeef);
637 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
638 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
639 EXPECT_LENW; EXPECT_EQW;
641 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
642 SetLastError(0xdeadbeef);
643 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
644 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
645 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
647 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
648 SetLastError(0xdeadbeef);
649 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
650 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
651 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
653 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
654 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
655 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
656 EXPECT_LENW;
658 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
659 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
660 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
661 EXPECT_LENW; EXPECT_EQW;
663 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
664 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
665 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
666 EXPECT_LENW; EXPECT_EQW;
668 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
669 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
670 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
671 EXPECT_LENW; EXPECT_EQW;
673 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
674 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
675 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
676 EXPECT_LENW; EXPECT_EQW;
678 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
679 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
680 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
681 EXPECT_LENW; EXPECT_EQW;
683 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
684 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
685 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
686 EXPECT_LENW; EXPECT_EQW;
688 STRINGSW("t/tt", "A/AM"); /* AM time marker */
689 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
690 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
691 EXPECT_LENW; EXPECT_EQW;
693 curtime.wHour = 13;
694 STRINGSW("t/tt", "P/PM"); /* PM time marker */
695 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
696 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
697 EXPECT_LENW; EXPECT_EQW;
699 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
700 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 EXPECT_LENW; EXPECT_EQW;
704 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
705 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
706 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
707 EXPECT_LENW; EXPECT_EQW;
709 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
710 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
711 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
712 EXPECT_LENW; EXPECT_EQW;
714 curtime.wHour = 14; /* change this to 14 or 2pm */
715 curtime.wMinute = 5;
716 curtime.wSecond = 3;
717 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 */
718 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
719 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
720 EXPECT_LENW; EXPECT_EQW;
722 curtime.wHour = 0;
723 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
724 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
725 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
726 EXPECT_LENW; EXPECT_EQW;
728 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
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 /* try to convert formatting strings with more than two letters
734 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
735 * NOTE: We expect any letter for which there is an upper case value
736 * we should see a replacement. For letters that DO NOT have
737 * upper case values we should see NO REPLACEMENT.
739 curtime.wHour = 8;
740 curtime.wMinute = 56;
741 curtime.wSecond = 13;
742 curtime.wMilliseconds = 22;
743 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
744 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
745 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
746 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
747 EXPECT_LENW; EXPECT_EQW;
749 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
750 lstrcpyW(buffer, Expected);
751 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
752 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
753 EXPECT_EQW;
755 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
756 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
757 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
758 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
759 EXPECT_LENW; EXPECT_EQW;
761 STRINGSW("'''", "'"); /* invalid quoted string */
762 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
763 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
764 EXPECT_LENW; EXPECT_EQW;
766 /* test that msdn suggested single quotation usage works as expected */
767 STRINGSW("''''", "'"); /* single quote mark */
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("''HHHHHH", "08"); /* Normal use */
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 /* and test for normal use of the single quotation mark */
778 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
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", "'HHHHHH"); /* Odd 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 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
789 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
790 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
791 EXPECT_LENW; EXPECT_EQW;
793 curtime.wHour = 25;
794 STRINGSW("'123'tt", ""); /* Invalid time */
795 SetLastError(0xdeadbeef);
796 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
797 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
798 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
800 curtime.wHour = 12;
801 curtime.wMonth = 60; /* Invalid */
802 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
803 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
804 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
805 EXPECT_LENW; EXPECT_EQW;
808 static void test_GetDateFormatA(void)
810 int ret;
811 SYSTEMTIME curtime;
812 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
813 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
814 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
815 char Broken[BUFFER_SIZE];
816 char short_day[10], month[10], genitive_month[10];
818 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
819 STRINGSA("ddd',' MMM dd yy","");
820 SetLastError(0xdeadbeef);
821 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
822 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
823 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
825 curtime.wYear = 2002;
826 curtime.wMonth = 5;
827 curtime.wDay = 4;
828 curtime.wDayOfWeek = 3;
829 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
830 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
831 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
832 EXPECT_LENA; EXPECT_EQA;
834 /* Same as above but with LOCALE_NOUSEROVERRIDE */
835 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
836 SetLastError(0xdeadbeef);
837 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
838 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
839 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
840 EXPECT_EQA;
842 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
843 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
844 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
845 EXPECT_LENA; EXPECT_EQA;
847 curtime.wHour = 36; /* Invalid */
848 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
849 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
850 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
851 EXPECT_LENA; EXPECT_EQA;
853 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
854 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
855 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
856 EXPECT_EQA;
858 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
859 SetLastError(0xdeadbeef);
860 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
861 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
862 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
864 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
865 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
866 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
867 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
868 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
870 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
871 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
872 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
873 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
874 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
875 "got an unexpected date string '%s'\n", buffer);
877 /* test for expected DATE_YEARMONTH behavior with null format */
878 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
879 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
880 SetLastError(0xdeadbeef);
881 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
882 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
883 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
884 EXPECT_EQA;
886 /* Test that using invalid DATE_* flags results in the correct error */
887 /* and return values */
888 STRINGSA("m/d/y", ""); /* Invalid flags */
889 SetLastError(0xdeadbeef);
890 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
891 &curtime, input, buffer, COUNTOF(buffer));
892 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
893 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
896 if (!ret)
898 win_skip("LANG_RUSSIAN locale data unavailable\n");
899 return;
902 /* month part should be in genitive form */
903 strcpy(genitive_month, buffer + 2);
904 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
905 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
906 strcpy(month, buffer);
907 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
909 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
910 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
911 strcpy(short_day, buffer);
913 STRINGSA("dd MMMMddd dd", "");
914 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
915 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 EXPECT_EQA;
919 STRINGSA("MMMMddd dd", "");
920 sprintf(Expected, "%s%s 04", month, short_day);
921 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
922 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
923 EXPECT_EQA;
925 STRINGSA("MMMMddd", "");
926 sprintf(Expected, "%s%s", month, short_day);
927 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
928 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
929 EXPECT_EQA;
931 STRINGSA("MMMMdd", "");
932 sprintf(Expected, "%s04", genitive_month);
933 sprintf(Broken, "%s04", month);
934 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
935 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
936 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
937 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
938 "Expected '%s', got '%s'\n", Expected, buffer);
940 STRINGSA("MMMMdd ddd", "");
941 sprintf(Expected, "%s04 %s", genitive_month, short_day);
942 sprintf(Broken, "%s04 %s", month, short_day);
943 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
944 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
945 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
946 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
947 "Expected '%s', got '%s'\n", Expected, buffer);
949 STRINGSA("dd dddMMMM", "");
950 sprintf(Expected, "04 %s%s", short_day, month);
951 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
952 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
953 EXPECT_EQA;
955 STRINGSA("dd dddMMMM ddd MMMMdd", "");
956 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
957 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
958 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
959 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
960 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
961 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
962 "Expected '%s', got '%s'\n", Expected, buffer);
964 /* with literal part */
965 STRINGSA("ddd',' MMMM dd", "");
966 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
967 sprintf(Broken, "%s, %s 04", short_day, month);
968 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
969 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
970 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
971 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
972 "Expected '%s', got '%s'\n", Expected, buffer);
975 static void test_GetDateFormatEx(void)
977 int ret;
978 SYSTEMTIME curtime;
979 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
981 if (!pGetDateFormatEx)
983 win_skip("GetDateFormatEx not supported\n");
984 return;
987 STRINGSW("",""); /* If flags are set, then format must be NULL */
988 SetLastError(0xdeadbeef);
989 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
990 input, buffer, COUNTOF(buffer), NULL);
991 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
992 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
993 EXPECT_EQW;
995 STRINGSW("",""); /* NULL buffer, len > 0 */
996 SetLastError(0xdeadbeef);
997 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
998 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
999 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1001 STRINGSW("",""); /* NULL buffer, len == 0 */
1002 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1003 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1004 EXPECT_LENW; EXPECT_EQW;
1006 STRINGSW("",""); /* Invalid flag combination */
1007 SetLastError(0xdeadbeef);
1008 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1009 input, NULL, 0, NULL);
1010 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1011 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1012 EXPECT_EQW;
1014 curtime.wYear = 2002;
1015 curtime.wMonth = 10;
1016 curtime.wDay = 23;
1017 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1018 curtime.wHour = 65432; /* Invalid */
1019 curtime.wMinute = 34512; /* Invalid */
1020 curtime.wSecond = 65535; /* Invalid */
1021 curtime.wMilliseconds = 12345;
1022 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1023 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1024 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1025 EXPECT_LENW; EXPECT_EQW;
1027 curtime.wYear = 2002;
1028 curtime.wMonth = 10;
1029 curtime.wDay = 23;
1030 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1031 curtime.wHour = 65432; /* Invalid */
1032 curtime.wMinute = 34512; /* Invalid */
1033 curtime.wSecond = 65535; /* Invalid */
1034 curtime.wMilliseconds = 12345;
1035 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1036 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1037 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1038 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1040 /* Limit tests */
1042 curtime.wYear = 1601;
1043 curtime.wMonth = 1;
1044 curtime.wDay = 1;
1045 curtime.wDayOfWeek = 0; /* Irrelevant */
1046 curtime.wHour = 0;
1047 curtime.wMinute = 0;
1048 curtime.wSecond = 0;
1049 curtime.wMilliseconds = 0;
1050 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1051 SetLastError(0xdeadbeef);
1052 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1053 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1054 EXPECT_LENW; EXPECT_EQW;
1056 curtime.wYear = 1600;
1057 curtime.wMonth = 12;
1058 curtime.wDay = 31;
1059 curtime.wDayOfWeek = 0; /* Irrelevant */
1060 curtime.wHour = 23;
1061 curtime.wMinute = 59;
1062 curtime.wSecond = 59;
1063 curtime.wMilliseconds = 999;
1064 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1065 SetLastError(0xdeadbeef);
1066 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1067 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1068 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1071 static void test_GetDateFormatW(void)
1073 int ret;
1074 SYSTEMTIME curtime;
1075 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1076 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1078 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1079 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1080 input, buffer, COUNTOF(buffer));
1081 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1083 win_skip("GetDateFormatW is not implemented\n");
1084 return;
1086 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1087 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1088 EXPECT_EQW;
1090 STRINGSW("",""); /* NULL buffer, len > 0 */
1091 SetLastError(0xdeadbeef);
1092 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1093 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1094 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1096 STRINGSW("",""); /* NULL buffer, len == 0 */
1097 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1098 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1099 EXPECT_LENW; EXPECT_EQW;
1101 curtime.wYear = 2002;
1102 curtime.wMonth = 10;
1103 curtime.wDay = 23;
1104 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1105 curtime.wHour = 65432; /* Invalid */
1106 curtime.wMinute = 34512; /* Invalid */
1107 curtime.wSecond = 65535; /* Invalid */
1108 curtime.wMilliseconds = 12345;
1109 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1110 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1111 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1112 EXPECT_LENW; EXPECT_EQW;
1114 /* Limit tests */
1116 curtime.wYear = 1601;
1117 curtime.wMonth = 1;
1118 curtime.wDay = 1;
1119 curtime.wDayOfWeek = 0; /* Irrelevant */
1120 curtime.wHour = 0;
1121 curtime.wMinute = 0;
1122 curtime.wSecond = 0;
1123 curtime.wMilliseconds = 0;
1124 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1125 SetLastError(0xdeadbeef);
1126 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1127 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1128 EXPECT_LENW; EXPECT_EQW;
1130 curtime.wYear = 1600;
1131 curtime.wMonth = 12;
1132 curtime.wDay = 31;
1133 curtime.wDayOfWeek = 0; /* Irrelevant */
1134 curtime.wHour = 23;
1135 curtime.wMinute = 59;
1136 curtime.wSecond = 59;
1137 curtime.wMilliseconds = 999;
1138 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1139 SetLastError(0xdeadbeef);
1140 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1141 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1142 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1146 #define CY_POS_LEFT 0
1147 #define CY_POS_RIGHT 1
1148 #define CY_POS_LEFT_SPACE 2
1149 #define CY_POS_RIGHT_SPACE 3
1151 static void test_GetCurrencyFormatA(void)
1153 static char szDot[] = { '.', '\0' };
1154 static char szComma[] = { ',', '\0' };
1155 static char szDollar[] = { '$', '\0' };
1156 int ret;
1157 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1158 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1159 CURRENCYFMTA format;
1161 memset(&format, 0, sizeof(format));
1163 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1164 SetLastError(0xdeadbeef);
1165 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1166 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1167 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1169 STRINGSA("23,53",""); /* Invalid character --> Error */
1170 SetLastError(0xdeadbeef);
1171 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1172 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1173 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1175 STRINGSA("--",""); /* Double '-' --> Error */
1176 SetLastError(0xdeadbeef);
1177 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1178 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1179 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1181 STRINGSA("0-",""); /* Trailing '-' --> Error */
1182 SetLastError(0xdeadbeef);
1183 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1184 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1185 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1187 STRINGSA("0..",""); /* Double '.' --> Error */
1188 SetLastError(0xdeadbeef);
1189 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1190 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1191 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1193 STRINGSA(" 0.1",""); /* Leading space --> Error */
1194 SetLastError(0xdeadbeef);
1195 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1196 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1197 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1199 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1200 SetLastError(0xdeadbeef);
1201 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1202 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1203 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1205 STRINGSA("2353",""); /* Format and flags given --> Error */
1206 SetLastError(0xdeadbeef);
1207 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1208 ok( !ret, "Expected ret == 0, got %d\n", ret);
1209 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1210 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1212 STRINGSA("2353",""); /* Invalid format --> Error */
1213 SetLastError(0xdeadbeef);
1214 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1215 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1216 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1218 STRINGSA("2353","$2,353.00"); /* Valid number */
1219 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1220 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1221 EXPECT_LENA; EXPECT_EQA;
1223 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1224 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1225 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1226 EXPECT_LENA; EXPECT_EQA;
1228 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1229 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1230 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1231 EXPECT_LENA; EXPECT_EQA;
1233 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1234 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1235 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1236 EXPECT_LENA; EXPECT_EQA;
1238 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1239 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1240 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1241 EXPECT_LENA; EXPECT_EQA;
1243 format.NumDigits = 0; /* No decimal separator */
1244 format.LeadingZero = 0;
1245 format.Grouping = 0; /* No grouping char */
1246 format.NegativeOrder = 0;
1247 format.PositiveOrder = CY_POS_LEFT;
1248 format.lpDecimalSep = szDot;
1249 format.lpThousandSep = szComma;
1250 format.lpCurrencySymbol = szDollar;
1252 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1253 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1254 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1255 EXPECT_LENA; EXPECT_EQA;
1257 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1258 STRINGSA("2353","$2353.0");
1259 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1260 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1261 EXPECT_LENA; EXPECT_EQA;
1263 format.Grouping = 2; /* Group by 100's */
1264 STRINGSA("2353","$23,53.0");
1265 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1266 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1267 EXPECT_LENA; EXPECT_EQA;
1269 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1270 format.Grouping = 3;
1271 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1272 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1273 EXPECT_LENA; EXPECT_EQA;
1275 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1276 format.NegativeOrder = 2;
1277 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1278 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1279 EXPECT_LENA; EXPECT_EQA;
1281 format.LeadingZero = 1; /* Always provide leading zero */
1282 STRINGSA(".5","$0.5");
1283 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1284 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1285 EXPECT_LENA; EXPECT_EQA;
1287 format.PositiveOrder = CY_POS_RIGHT;
1288 STRINGSA("1","1.0$");
1289 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1290 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1291 EXPECT_LENA; EXPECT_EQA;
1293 format.PositiveOrder = CY_POS_LEFT_SPACE;
1294 STRINGSA("1","$ 1.0");
1295 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1296 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1297 EXPECT_LENA; EXPECT_EQA;
1299 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1300 STRINGSA("1","1.0 $");
1301 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1302 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1303 EXPECT_LENA; EXPECT_EQA;
1305 format.NegativeOrder = 0;
1306 STRINGSA("-1","($1.0)");
1307 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1308 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1309 EXPECT_LENA; EXPECT_EQA;
1311 format.NegativeOrder = 1;
1312 STRINGSA("-1","-$1.0");
1313 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1314 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1315 EXPECT_LENA; EXPECT_EQA;
1317 format.NegativeOrder = 2;
1318 STRINGSA("-1","$-1.0");
1319 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1320 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1321 EXPECT_LENA; EXPECT_EQA;
1323 format.NegativeOrder = 3;
1324 STRINGSA("-1","$1.0-");
1325 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1326 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1327 EXPECT_LENA; EXPECT_EQA;
1329 format.NegativeOrder = 4;
1330 STRINGSA("-1","(1.0$)");
1331 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1332 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1333 EXPECT_LENA; EXPECT_EQA;
1335 format.NegativeOrder = 5;
1336 STRINGSA("-1","-1.0$");
1337 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1338 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1339 EXPECT_LENA; EXPECT_EQA;
1341 format.NegativeOrder = 6;
1342 STRINGSA("-1","1.0-$");
1343 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1344 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1345 EXPECT_LENA; EXPECT_EQA;
1347 format.NegativeOrder = 7;
1348 STRINGSA("-1","1.0$-");
1349 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1350 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1351 EXPECT_LENA; EXPECT_EQA;
1353 format.NegativeOrder = 8;
1354 STRINGSA("-1","-1.0 $");
1355 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1356 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1357 EXPECT_LENA; EXPECT_EQA;
1359 format.NegativeOrder = 9;
1360 STRINGSA("-1","-$ 1.0");
1361 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1362 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1363 EXPECT_LENA; EXPECT_EQA;
1365 format.NegativeOrder = 10;
1366 STRINGSA("-1","1.0 $-");
1367 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1368 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1369 EXPECT_LENA; EXPECT_EQA;
1371 format.NegativeOrder = 11;
1372 STRINGSA("-1","$ 1.0-");
1373 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1374 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1375 EXPECT_LENA; EXPECT_EQA;
1377 format.NegativeOrder = 12;
1378 STRINGSA("-1","$ -1.0");
1379 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1380 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1381 EXPECT_LENA; EXPECT_EQA;
1383 format.NegativeOrder = 13;
1384 STRINGSA("-1","1.0- $");
1385 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1386 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1387 EXPECT_LENA; EXPECT_EQA;
1389 format.NegativeOrder = 14;
1390 STRINGSA("-1","($ 1.0)");
1391 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1392 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1393 EXPECT_LENA; EXPECT_EQA;
1395 format.NegativeOrder = 15;
1396 STRINGSA("-1","(1.0 $)");
1397 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1398 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1399 EXPECT_LENA; EXPECT_EQA;
1402 #define NEG_PARENS 0 /* "(1.1)" */
1403 #define NEG_LEFT 1 /* "-1.1" */
1404 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1405 #define NEG_RIGHT 3 /* "1.1-" */
1406 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1408 static void test_GetNumberFormatA(void)
1410 static char szDot[] = { '.', '\0' };
1411 static char szComma[] = { ',', '\0' };
1412 int ret;
1413 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1414 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1415 NUMBERFMTA format;
1417 memset(&format, 0, sizeof(format));
1419 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1420 SetLastError(0xdeadbeef);
1421 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1422 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1423 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1425 STRINGSA("23,53",""); /* Invalid character --> Error */
1426 SetLastError(0xdeadbeef);
1427 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1428 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1429 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1431 STRINGSA("--",""); /* Double '-' --> Error */
1432 SetLastError(0xdeadbeef);
1433 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1434 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1435 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1437 STRINGSA("0-",""); /* Trailing '-' --> Error */
1438 SetLastError(0xdeadbeef);
1439 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1440 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1441 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1443 STRINGSA("0..",""); /* Double '.' --> Error */
1444 SetLastError(0xdeadbeef);
1445 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1446 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1447 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1449 STRINGSA(" 0.1",""); /* Leading space --> Error */
1450 SetLastError(0xdeadbeef);
1451 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1452 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1453 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1455 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1456 SetLastError(0xdeadbeef);
1457 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1458 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1459 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1461 STRINGSA("2353",""); /* Format and flags given --> Error */
1462 SetLastError(0xdeadbeef);
1463 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1464 ok( !ret, "Expected ret == 0, got %d\n", ret);
1465 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1466 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1468 STRINGSA("2353",""); /* Invalid format --> Error */
1469 SetLastError(0xdeadbeef);
1470 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1471 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1472 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1474 STRINGSA("2353","2,353.00"); /* Valid number */
1475 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1476 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1477 EXPECT_LENA; EXPECT_EQA;
1479 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1480 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1481 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1482 EXPECT_LENA; EXPECT_EQA;
1484 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1485 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1486 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1487 EXPECT_LENA; EXPECT_EQA;
1489 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1490 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1491 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1492 EXPECT_LENA; EXPECT_EQA;
1494 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1495 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1496 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1497 EXPECT_LENA; EXPECT_EQA;
1499 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1500 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1501 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1502 EXPECT_LENA; EXPECT_EQA;
1504 format.NumDigits = 0; /* No decimal separator */
1505 format.LeadingZero = 0;
1506 format.Grouping = 0; /* No grouping char */
1507 format.NegativeOrder = 0;
1508 format.lpDecimalSep = szDot;
1509 format.lpThousandSep = szComma;
1511 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1512 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1513 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1514 EXPECT_LENA; EXPECT_EQA;
1516 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1517 STRINGSA("2353","2353.0");
1518 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1519 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1520 EXPECT_LENA; EXPECT_EQA;
1522 format.Grouping = 2; /* Group by 100's */
1523 STRINGSA("2353","23,53.0");
1524 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1526 EXPECT_LENA; EXPECT_EQA;
1528 STRINGSA("235","235.0"); /* Grouping of a positive number */
1529 format.Grouping = 3;
1530 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1531 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1532 EXPECT_LENA; EXPECT_EQA;
1534 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1535 format.NegativeOrder = NEG_LEFT;
1536 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1537 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1538 EXPECT_LENA; EXPECT_EQA;
1540 format.LeadingZero = 1; /* Always provide leading zero */
1541 STRINGSA(".5","0.5");
1542 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1543 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1544 EXPECT_LENA; EXPECT_EQA;
1546 format.NegativeOrder = NEG_PARENS;
1547 STRINGSA("-1","(1.0)");
1548 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1549 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1550 EXPECT_LENA; EXPECT_EQA;
1552 format.NegativeOrder = NEG_LEFT;
1553 STRINGSA("-1","-1.0");
1554 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1555 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1556 EXPECT_LENA; EXPECT_EQA;
1558 format.NegativeOrder = NEG_LEFT_SPACE;
1559 STRINGSA("-1","- 1.0");
1560 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1562 EXPECT_LENA; EXPECT_EQA;
1564 format.NegativeOrder = NEG_RIGHT;
1565 STRINGSA("-1","1.0-");
1566 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1567 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1568 EXPECT_LENA; EXPECT_EQA;
1570 format.NegativeOrder = NEG_RIGHT_SPACE;
1571 STRINGSA("-1","1.0 -");
1572 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1573 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1574 EXPECT_LENA; EXPECT_EQA;
1576 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1578 if (IsValidLocale(lcid, 0))
1580 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1581 Expected[3] = 160; /* Non breaking space */
1582 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1583 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1584 EXPECT_LENA; EXPECT_EQA;
1588 struct comparestringa_entry {
1589 LCID lcid;
1590 DWORD flags;
1591 const char *first;
1592 int first_len;
1593 const char *second;
1594 int second_len;
1595 int ret;
1598 static const struct comparestringa_entry comparestringa_data[] = {
1599 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1600 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1601 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1602 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1603 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1604 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1605 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1606 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1607 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1608 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1609 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1610 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1611 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1612 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1613 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1614 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1615 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1616 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1617 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1618 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1619 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1620 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1621 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1622 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1623 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1624 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1625 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1626 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1627 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1628 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1629 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1630 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1631 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1632 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1633 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1634 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1635 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1636 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1637 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1638 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1639 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1640 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1641 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1642 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1645 static void test_CompareStringA(void)
1647 int ret, i;
1648 char a[256];
1649 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1651 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1653 const struct comparestringa_entry *entry = &comparestringa_data[i];
1655 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1656 entry->second, entry->second_len);
1657 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1660 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1661 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1663 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1664 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1666 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1667 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1669 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1670 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1672 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1674 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1675 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1677 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1678 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1680 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1681 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1683 /* test for CompareStringA flags */
1684 SetLastError(0xdeadbeef);
1685 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1686 ok(GetLastError() == ERROR_INVALID_FLAGS,
1687 "unexpected error code %d\n", GetLastError());
1688 ok(!ret, "CompareStringA must fail with invalid flag\n");
1690 SetLastError(0xdeadbeef);
1691 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1692 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1693 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1694 /* end of test for CompareStringA flags */
1696 ret = lstrcmpA("", "");
1697 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1699 ret = lstrcmpA(NULL, NULL);
1700 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1702 ret = lstrcmpA("", NULL);
1703 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1705 ret = lstrcmpA(NULL, "");
1706 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1709 if (0) { /* this requires collation table patch to make it MS compatible */
1710 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1711 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1713 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1714 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1716 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1717 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1719 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1720 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1722 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1723 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1725 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1726 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1728 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1729 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1731 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1732 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1734 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1735 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1737 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1738 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1740 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1741 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1743 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1744 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1748 /* WinXP handles embedded NULLs differently than earlier versions */
1749 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1750 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1752 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1753 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);
1755 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1756 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1758 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1759 ok(ret == CSTR_EQUAL || /* win2k */
1760 ret == CSTR_GREATER_THAN,
1761 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1763 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1764 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1766 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1767 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1769 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1770 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1772 ret = lstrcmpiA("#", ".");
1773 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1775 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1777 /* \xB9 character lies between a and b */
1778 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1779 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1780 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1781 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1783 memset(a, 'a', sizeof(a));
1784 SetLastError(0xdeadbeef);
1785 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1786 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1787 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1790 static void test_CompareStringW(void)
1792 WCHAR *str1, *str2;
1793 SYSTEM_INFO si;
1794 DWORD old_prot;
1795 BOOL success;
1796 char *buf;
1797 int ret;
1799 GetSystemInfo(&si);
1800 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1801 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1802 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1803 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1804 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1805 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1807 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
1808 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
1809 *str1 = 'A';
1810 *str2 = 'B';
1812 /* CompareStringW should abort on the first non-matching character */
1813 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
1814 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
1816 success = VirtualFree(buf, 0, MEM_RELEASE);
1817 ok(success, "VirtualFree failed with %u\n", GetLastError());
1820 struct comparestringex_test {
1821 const char *locale;
1822 DWORD flags;
1823 const WCHAR first[2];
1824 const WCHAR second[2];
1825 INT ret;
1826 INT broken;
1827 BOOL todo;
1830 static const struct comparestringex_test comparestringex_tests[] = {
1831 /* default behavior */
1832 { /* 0 */
1833 "tr-TR", 0,
1834 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
1836 { /* 1 */
1837 "tr-TR", 0,
1838 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1840 { /* 2 */
1841 "tr-TR", 0,
1842 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1844 { /* 3 */
1845 "tr-TR", 0,
1846 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1848 { /* 4 */
1849 "tr-TR", 0,
1850 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1852 { /* 5 */
1853 "tr-TR", 0,
1854 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1856 /* with NORM_IGNORECASE */
1857 { /* 6 */
1858 "tr-TR", NORM_IGNORECASE,
1859 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
1861 { /* 7 */
1862 "tr-TR", NORM_IGNORECASE,
1863 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1865 { /* 8 */
1866 "tr-TR", NORM_IGNORECASE,
1867 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1869 { /* 9 */
1870 "tr-TR", NORM_IGNORECASE,
1871 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1873 { /* 10 */
1874 "tr-TR", NORM_IGNORECASE,
1875 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1877 { /* 11 */
1878 "tr-TR", NORM_IGNORECASE,
1879 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1881 /* with NORM_LINGUISTIC_CASING */
1882 { /* 12 */
1883 "tr-TR", NORM_LINGUISTIC_CASING,
1884 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1886 { /* 13 */
1887 "tr-TR", NORM_LINGUISTIC_CASING,
1888 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1890 { /* 14 */
1891 "tr-TR", NORM_LINGUISTIC_CASING,
1892 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1894 { /* 15 */
1895 "tr-TR", NORM_LINGUISTIC_CASING,
1896 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1898 { /* 16 */
1899 "tr-TR", NORM_LINGUISTIC_CASING,
1900 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1902 { /* 17 */
1903 "tr-TR", NORM_LINGUISTIC_CASING,
1904 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1906 /* with LINGUISTIC_IGNORECASE */
1907 { /* 18 */
1908 "tr-TR", LINGUISTIC_IGNORECASE,
1909 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
1911 { /* 19 */
1912 "tr-TR", LINGUISTIC_IGNORECASE,
1913 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1915 { /* 20 */
1916 "tr-TR", LINGUISTIC_IGNORECASE,
1917 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1919 { /* 21 */
1920 "tr-TR", LINGUISTIC_IGNORECASE,
1921 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1923 { /* 22 */
1924 "tr-TR", LINGUISTIC_IGNORECASE,
1925 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1927 { /* 23 */
1928 "tr-TR", LINGUISTIC_IGNORECASE,
1929 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1931 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
1932 { /* 24 */
1933 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1934 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1936 { /* 25 */
1937 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1938 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
1940 { /* 26 */
1941 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1942 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1944 { /* 27 */
1945 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1946 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1948 { /* 28 */
1949 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1950 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1952 { /* 29 */
1953 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1954 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1956 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
1957 { /* 30 */
1958 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1959 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1961 { /* 31 */
1962 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1963 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1965 { /* 32 */
1966 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1967 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1969 { /* 33 */
1970 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1971 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1973 { /* 34 */
1974 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1975 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1977 { /* 35 */
1978 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1979 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1983 static void test_CompareStringEx(void)
1985 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
1986 WCHAR locale[6];
1987 INT ret, i;
1989 /* CompareStringEx is only available on Vista+ */
1990 if (!pCompareStringEx)
1992 win_skip("CompareStringEx not supported\n");
1993 return;
1996 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
1998 const struct comparestringex_test *e = &comparestringex_tests[i];
2000 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2001 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2002 todo_wine_if (e->todo)
2003 ok(ret == e->ret || broken(ret == e->broken),
2004 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2009 static void test_LCMapStringA(void)
2011 int ret, ret2;
2012 char buf[256], buf2[256];
2013 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2014 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2015 static const char symbols_stripped[] = "justateststring1";
2017 SetLastError(0xdeadbeef);
2018 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2019 lower_case, -1, buf, sizeof(buf));
2020 ok(ret == lstrlenA(lower_case) + 1,
2021 "ret %d, error %d, expected value %d\n",
2022 ret, GetLastError(), lstrlenA(lower_case) + 1);
2023 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2025 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2026 upper_case, -1, buf, sizeof(buf));
2027 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2028 ok(GetLastError() == ERROR_INVALID_FLAGS,
2029 "unexpected error code %d\n", GetLastError());
2031 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
2032 upper_case, -1, buf, sizeof(buf));
2033 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
2034 ok(GetLastError() == ERROR_INVALID_FLAGS,
2035 "unexpected error code %d\n", GetLastError());
2037 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2038 upper_case, -1, buf, sizeof(buf));
2039 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
2040 ok(GetLastError() == ERROR_INVALID_FLAGS,
2041 "unexpected error code %d\n", GetLastError());
2043 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2044 upper_case, -1, buf, sizeof(buf));
2045 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
2046 ok(GetLastError() == ERROR_INVALID_FLAGS,
2047 "unexpected error code %d\n", GetLastError());
2049 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2050 SetLastError(0xdeadbeef);
2051 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
2052 upper_case, -1, buf, sizeof(buf));
2053 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2054 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
2056 /* test LCMAP_LOWERCASE */
2057 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2058 upper_case, -1, buf, sizeof(buf));
2059 ok(ret == lstrlenA(upper_case) + 1,
2060 "ret %d, error %d, expected value %d\n",
2061 ret, GetLastError(), lstrlenA(upper_case) + 1);
2062 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2064 /* test LCMAP_UPPERCASE */
2065 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2066 lower_case, -1, buf, sizeof(buf));
2067 ok(ret == lstrlenA(lower_case) + 1,
2068 "ret %d, error %d, expected value %d\n",
2069 ret, GetLastError(), lstrlenA(lower_case) + 1);
2070 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2072 /* test buffer overflow */
2073 SetLastError(0xdeadbeef);
2074 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2075 lower_case, -1, buf, 4);
2076 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2077 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2079 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2080 lstrcpyA(buf, lower_case);
2081 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2082 buf, -1, buf, sizeof(buf));
2083 if (!ret) /* Win9x */
2084 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2085 else
2087 ok(ret == lstrlenA(lower_case) + 1,
2088 "ret %d, error %d, expected value %d\n",
2089 ret, GetLastError(), lstrlenA(lower_case) + 1);
2090 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2092 lstrcpyA(buf, upper_case);
2093 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2094 buf, -1, buf, sizeof(buf));
2095 if (!ret) /* Win9x */
2096 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2097 else
2099 ok(ret == lstrlenA(upper_case) + 1,
2100 "ret %d, error %d, expected value %d\n",
2101 ret, GetLastError(), lstrlenA(lower_case) + 1);
2102 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2105 /* otherwise src == dst should fail */
2106 SetLastError(0xdeadbeef);
2107 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2108 buf, 10, buf, sizeof(buf));
2109 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2110 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2111 "unexpected error code %d\n", GetLastError());
2112 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2114 /* test whether '\0' is always appended */
2115 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2116 upper_case, -1, buf, sizeof(buf));
2117 ok(ret, "LCMapStringA must succeed\n");
2118 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2119 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2120 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2121 ok(ret2, "LCMapStringA must succeed\n");
2122 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2123 ok(ret == ret2, "lengths of sort keys must be equal\n");
2124 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2126 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2127 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2128 upper_case, -1, buf, sizeof(buf));
2129 ok(ret, "LCMapStringA must succeed\n");
2130 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2131 lower_case, -1, buf2, sizeof(buf2));
2132 ok(ret2, "LCMapStringA must succeed\n");
2133 ok(ret == ret2, "lengths of sort keys must be equal\n");
2134 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2136 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2137 results from plain LCMAP_SORTKEY on Vista */
2139 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2140 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2141 lower_case, -1, buf, sizeof(buf));
2142 ok(ret, "LCMapStringA must succeed\n");
2143 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2144 symbols_stripped, -1, buf2, sizeof(buf2));
2145 ok(ret2, "LCMapStringA must succeed\n");
2146 ok(ret == ret2, "lengths of sort keys must be equal\n");
2147 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2149 /* test NORM_IGNORENONSPACE */
2150 lstrcpyA(buf, "foo");
2151 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2152 lower_case, -1, buf, sizeof(buf));
2153 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2154 lstrlenA(lower_case) + 1, ret);
2155 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2157 /* test NORM_IGNORESYMBOLS */
2158 lstrcpyA(buf, "foo");
2159 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2160 lower_case, -1, buf, sizeof(buf));
2161 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2162 lstrlenA(symbols_stripped) + 1, ret);
2163 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2165 /* test srclen = 0 */
2166 SetLastError(0xdeadbeef);
2167 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2168 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2169 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2170 "unexpected error code %d\n", GetLastError());
2173 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2175 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2177 int ret, ret2;
2178 WCHAR buf[256], buf2[256];
2179 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2181 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2182 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2183 if (broken(ret))
2184 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
2185 else
2187 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
2188 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2189 func_name, GetLastError());
2192 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
2193 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2194 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
2195 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2196 func_name, GetLastError());
2198 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2199 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2200 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
2201 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2202 func_name, GetLastError());
2204 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2205 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2206 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
2207 func_name);
2208 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
2209 func_name, GetLastError());
2211 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
2212 SetLastError(0xdeadbeef);
2213 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
2214 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2215 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
2216 func_name, GetLastError());
2217 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
2219 /* test LCMAP_LOWERCASE */
2220 ret = func_ptr(LCMAP_LOWERCASE,
2221 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2222 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2223 ret, GetLastError(), lstrlenW(upper_case) + 1);
2224 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2226 /* test LCMAP_UPPERCASE */
2227 ret = func_ptr(LCMAP_UPPERCASE,
2228 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2229 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2230 ret, GetLastError(), lstrlenW(lower_case) + 1);
2231 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2233 /* test buffer overflow */
2234 SetLastError(0xdeadbeef);
2235 ret = func_ptr(LCMAP_UPPERCASE,
2236 lower_case, -1, buf, 4);
2237 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2238 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2240 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2241 lstrcpyW(buf, lower_case);
2242 ret = func_ptr(LCMAP_UPPERCASE,
2243 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2244 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2245 ret, GetLastError(), lstrlenW(lower_case) + 1);
2246 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2248 lstrcpyW(buf, upper_case);
2249 ret = func_ptr(LCMAP_LOWERCASE,
2250 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2251 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2252 ret, GetLastError(), lstrlenW(lower_case) + 1);
2253 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2255 /* otherwise src == dst should fail */
2256 SetLastError(0xdeadbeef);
2257 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2258 buf, 10, buf, sizeof(buf));
2259 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2260 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2261 "%s unexpected error code %d\n", func_name, GetLastError());
2262 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2264 /* test whether '\0' is always appended */
2265 ret = func_ptr(LCMAP_SORTKEY,
2266 upper_case, -1, buf, sizeof(buf));
2267 ok(ret, "%s func_ptr must succeed\n", func_name);
2268 ret2 = func_ptr(LCMAP_SORTKEY,
2269 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2270 ok(ret, "%s func_ptr must succeed\n", func_name);
2271 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2272 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2274 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2275 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2276 upper_case, -1, buf, sizeof(buf));
2277 ok(ret, "%s func_ptr must succeed\n", func_name);
2278 ret2 = func_ptr(LCMAP_SORTKEY,
2279 lower_case, -1, buf2, sizeof(buf2));
2280 ok(ret2, "%s func_ptr must succeed\n", func_name);
2281 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2282 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2284 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2285 results from plain LCMAP_SORTKEY on Vista */
2287 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2288 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2289 lower_case, -1, buf, sizeof(buf));
2290 ok(ret, "%s func_ptr must succeed\n", func_name);
2291 ret2 = func_ptr(LCMAP_SORTKEY,
2292 symbols_stripped, -1, buf2, sizeof(buf2));
2293 ok(ret2, "%s func_ptr must succeed\n", func_name);
2294 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2295 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2297 /* test NORM_IGNORENONSPACE */
2298 lstrcpyW(buf, fooW);
2299 ret = func_ptr(NORM_IGNORENONSPACE,
2300 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2301 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2302 lstrlenW(lower_case) + 1, ret);
2303 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2305 /* test NORM_IGNORESYMBOLS */
2306 lstrcpyW(buf, fooW);
2307 ret = func_ptr(NORM_IGNORESYMBOLS,
2308 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2309 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2310 lstrlenW(symbols_stripped) + 1, ret);
2311 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2313 /* test srclen = 0 */
2314 SetLastError(0xdeadbeef);
2315 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2316 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2317 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2318 "%s unexpected error code %d\n", func_name, GetLastError());
2321 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2323 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2326 static void test_LCMapStringW(void)
2328 int ret;
2329 WCHAR buf[256];
2331 trace("testing LCMapStringW\n");
2333 SetLastError(0xdeadbeef);
2334 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2335 todo_wine {
2336 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2337 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2340 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2343 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2345 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2348 static void test_LCMapStringEx(void)
2350 int ret;
2351 WCHAR buf[256];
2353 if (!pLCMapStringEx)
2355 win_skip( "LCMapStringEx not available\n" );
2356 return;
2359 trace("testing LCMapStringEx\n");
2361 SetLastError(0xdeadbeef);
2362 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2363 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2364 todo_wine {
2365 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2366 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2369 /* test reserved parameters */
2370 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2371 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2372 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2373 ret, GetLastError(), lstrlenW(upper_case) + 1);
2374 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2376 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2377 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2378 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2379 ret, GetLastError(), lstrlenW(upper_case) + 1);
2380 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2382 /* crashes on native */
2383 if(0)
2384 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2385 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2387 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2390 struct neutralsublang_name_t {
2391 WCHAR name[3];
2392 LCID lcid;
2393 int todo;
2396 static const struct neutralsublang_name_t neutralsublang_names[] = {
2397 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2398 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2399 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2400 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2401 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2402 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2403 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2404 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2405 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2406 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2407 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2408 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2409 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2410 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2411 { {0} }
2414 static void test_LocaleNameToLCID(void)
2416 LCID lcid;
2417 INT ret;
2418 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2419 static const WCHAR enW[] = {'e','n',0};
2421 if (!pLocaleNameToLCID)
2423 win_skip( "LocaleNameToLCID not available\n" );
2424 return;
2427 /* special cases */
2428 buffer[0] = 0;
2429 SetLastError(0xdeadbeef);
2430 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2431 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2432 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2433 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2434 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2435 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2437 buffer[0] = 0;
2438 SetLastError(0xdeadbeef);
2439 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2440 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2441 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2442 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2443 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2444 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2446 buffer[0] = 0;
2447 SetLastError(0xdeadbeef);
2448 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2449 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2450 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2451 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2452 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2454 /* bad name */
2455 SetLastError(0xdeadbeef);
2456 lcid = pLocaleNameToLCID(fooW, 0);
2457 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2458 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
2460 /* english neutral name */
2461 lcid = pLocaleNameToLCID(enW, 0);
2462 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2463 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2464 if (lcid)
2466 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2468 while (*ptr->name)
2470 lcid = pLocaleNameToLCID(ptr->name, 0);
2471 todo_wine_if (ptr->todo)
2472 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2473 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2475 *buffer = 0;
2476 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2477 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2478 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2479 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2481 ptr++;
2486 /* this requires collation table patch to make it MS compatible */
2487 static const char * const strings_sorted[] =
2489 "'",
2490 "-",
2491 "!",
2492 "\"",
2493 ".",
2494 ":",
2495 "\\",
2496 "_",
2497 "`",
2498 "{",
2499 "}",
2500 "+",
2501 "0",
2502 "1",
2503 "2",
2504 "3",
2505 "4",
2506 "5",
2507 "6",
2508 "7",
2509 "8",
2510 "9",
2511 "a",
2512 "A",
2513 "b",
2514 "B",
2515 "c",
2519 static const char * const strings[] =
2521 "C",
2522 "\"",
2523 "9",
2524 "'",
2525 "}",
2526 "-",
2527 "7",
2528 "+",
2529 "`",
2530 "1",
2531 "a",
2532 "5",
2533 "\\",
2534 "8",
2535 "B",
2536 "3",
2537 "_",
2538 "6",
2539 "{",
2540 "2",
2541 "c",
2542 "4",
2543 "!",
2544 "0",
2545 "A",
2546 ":",
2547 "b",
2551 static int compare_string1(const void *e1, const void *e2)
2553 const char *s1 = *(const char *const *)e1;
2554 const char *s2 = *(const char *const *)e2;
2556 return lstrcmpA(s1, s2);
2559 static int compare_string2(const void *e1, const void *e2)
2561 const char *s1 = *(const char *const *)e1;
2562 const char *s2 = *(const char *const *)e2;
2564 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2567 static int compare_string3(const void *e1, const void *e2)
2569 const char *s1 = *(const char *const *)e1;
2570 const char *s2 = *(const char *const *)e2;
2571 char key1[256], key2[256];
2573 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2574 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2575 return strcmp(key1, key2);
2578 static void test_sorting(void)
2580 char buf[256];
2581 char **str_buf = (char **)buf;
2582 int i;
2584 assert(sizeof(buf) >= sizeof(strings));
2586 /* 1. sort using lstrcmpA */
2587 memcpy(buf, strings, sizeof(strings));
2588 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2589 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2591 ok(!strcmp(strings_sorted[i], str_buf[i]),
2592 "qsort using lstrcmpA failed for element %d\n", i);
2594 /* 2. sort using CompareStringA */
2595 memcpy(buf, strings, sizeof(strings));
2596 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2597 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2599 ok(!strcmp(strings_sorted[i], str_buf[i]),
2600 "qsort using CompareStringA failed for element %d\n", i);
2602 /* 3. sort using sort keys */
2603 memcpy(buf, strings, sizeof(strings));
2604 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2605 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2607 ok(!strcmp(strings_sorted[i], str_buf[i]),
2608 "qsort using sort keys failed for element %d\n", i);
2612 static void test_FoldStringA(void)
2614 int ret, i, j;
2615 BOOL is_special;
2616 char src[256], dst[256];
2617 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2618 static const char digits_dst[] = { '1','2','3','\0' };
2619 static const char composite_src[] =
2621 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2622 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2623 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2624 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2625 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2626 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2627 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2628 0xfb,0xfc,0xfd,0xff,'\0'
2630 static const char composite_dst[] =
2632 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2633 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2634 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2635 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2636 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2637 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2638 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2639 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2640 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2641 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2642 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2643 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2644 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2645 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2646 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2648 static const char composite_dst_alt[] =
2650 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2651 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2652 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2653 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2654 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2655 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2656 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2657 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2658 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2659 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2660 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2661 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2662 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2663 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2664 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2666 static const char ligatures_src[] =
2668 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2670 static const char ligatures_dst[] =
2672 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2674 static const struct special
2676 char src;
2677 char dst[4];
2678 } foldczone_special[] =
2680 /* src dst */
2681 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2682 { 0x98, { 0x20, 0x7e, 0x00 } },
2683 { 0x99, { 0x54, 0x4d, 0x00 } },
2684 { 0xa0, { 0x20, 0x00 } },
2685 { 0xa8, { 0x20, 0xa8, 0x00 } },
2686 { 0xaa, { 0x61, 0x00 } },
2687 { 0xaf, { 0x20, 0xaf, 0x00 } },
2688 { 0xb2, { 0x32, 0x00 } },
2689 { 0xb3, { 0x33, 0x00 } },
2690 { 0xb4, { 0x20, 0xb4, 0x00 } },
2691 { 0xb8, { 0x20, 0xb8, 0x00 } },
2692 { 0xb9, { 0x31, 0x00 } },
2693 { 0xba, { 0x6f, 0x00 } },
2694 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2695 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2696 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2697 { 0x00 }
2700 if (!pFoldStringA)
2701 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2703 /* these tests are locale specific */
2704 if (GetACP() != 1252)
2706 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2707 return;
2710 /* MAP_FOLDDIGITS */
2711 SetLastError(0);
2712 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2713 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2715 win_skip("FoldStringA is not implemented\n");
2716 return;
2718 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2719 ok(strcmp(dst, digits_dst) == 0,
2720 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2721 for (i = 1; i < 256; i++)
2723 if (!strchr(digits_src, i))
2725 src[0] = i;
2726 src[1] = '\0';
2727 SetLastError(0);
2728 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2729 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2730 ok(dst[0] == src[0],
2731 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2735 /* MAP_EXPAND_LIGATURES */
2736 SetLastError(0);
2737 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2738 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2739 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2740 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2741 ok(strcmp(dst, ligatures_dst) == 0,
2742 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2743 for (i = 1; i < 256; i++)
2745 if (!strchr(ligatures_src, i))
2747 src[0] = i;
2748 src[1] = '\0';
2749 SetLastError(0);
2750 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2751 if (ret == 3)
2753 /* Vista */
2754 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2755 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2756 "Got %s for %d\n", dst, i);
2758 else
2760 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2761 ok(dst[0] == src[0],
2762 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2768 /* MAP_COMPOSITE */
2769 SetLastError(0);
2770 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2771 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2772 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2773 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2774 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2776 for (i = 1; i < 256; i++)
2778 if (!strchr(composite_src, i))
2780 src[0] = i;
2781 src[1] = '\0';
2782 SetLastError(0);
2783 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2784 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2785 ok(dst[0] == src[0],
2786 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2787 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2791 /* MAP_FOLDCZONE */
2792 for (i = 1; i < 256; i++)
2794 src[0] = i;
2795 src[1] = '\0';
2796 SetLastError(0);
2797 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2798 is_special = FALSE;
2799 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2801 if (foldczone_special[j].src == src[0])
2803 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2804 "Expected ret == 2 or %d, got %d, error %d\n",
2805 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2806 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2807 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2808 (unsigned char)src[0]);
2809 is_special = TRUE;
2812 if (! is_special)
2814 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2815 ok(src[0] == dst[0],
2816 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2817 (unsigned char)src[0], (unsigned char)dst[0]);
2821 /* MAP_PRECOMPOSED */
2822 for (i = 1; i < 256; i++)
2824 src[0] = i;
2825 src[1] = '\0';
2826 SetLastError(0);
2827 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2828 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2829 ok(src[0] == dst[0],
2830 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2831 (unsigned char)src[0], (unsigned char)dst[0]);
2835 static void test_FoldStringW(void)
2837 int ret;
2838 unsigned int i, j;
2839 WCHAR src[256], dst[256], ch, prev_ch = 1;
2840 static const DWORD badFlags[] =
2843 MAP_PRECOMPOSED|MAP_COMPOSITE,
2844 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2845 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2847 /* Ranges of digits 0-9 : Must be sorted! */
2848 static const WCHAR digitRanges[] =
2850 0x0030, /* '0'-'9' */
2851 0x0660, /* Eastern Arabic */
2852 0x06F0, /* Arabic - Hindu */
2853 0x07C0, /* Nko */
2854 0x0966, /* Devengari */
2855 0x09E6, /* Bengalii */
2856 0x0A66, /* Gurmukhi */
2857 0x0AE6, /* Gujarati */
2858 0x0B66, /* Oriya */
2859 0x0BE6, /* Tamil - No 0 */
2860 0x0C66, /* Telugu */
2861 0x0CE6, /* Kannada */
2862 0x0D66, /* Maylayalam */
2863 0x0DE6, /* Sinhala Lith */
2864 0x0E50, /* Thai */
2865 0x0ED0, /* Laos */
2866 0x0F20, /* Tibet */
2867 0x0F29, /* Tibet half - 0 is out of sequence */
2868 0x1040, /* Myanmar */
2869 0x1090, /* Myanmar Shan */
2870 0x1368, /* Ethiopic - no 0 */
2871 0x17E0, /* Khmer */
2872 0x1810, /* Mongolian */
2873 0x1946, /* Limbu */
2874 0x19D0, /* New Tai Lue */
2875 0x1A80, /* Tai Tham Hora */
2876 0x1A90, /* Tai Tham Tham */
2877 0x1B50, /* Balinese */
2878 0x1BB0, /* Sundanese */
2879 0x1C40, /* Lepcha */
2880 0x1C50, /* Ol Chiki */
2881 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2882 0x2080, /* Subscript */
2883 0x245F, /* Circled - 0 is out of sequence */
2884 0x2473, /* Bracketed */
2885 0x2487, /* Full stop */
2886 0x24F4, /* Double Circled */
2887 0x2775, /* Inverted circled - No 0 */
2888 0x277F, /* Patterned circled - No 0 */
2889 0x2789, /* Inverted Patterned circled - No 0 */
2890 0x3020, /* Hangzhou */
2891 0xA620, /* Vai */
2892 0xA8D0, /* Saurashtra */
2893 0xA900, /* Kayah Li */
2894 0xA9D0, /* Javanese */
2895 0xA9F0, /* Myanmar Tai Laing */
2896 0xAA50, /* Cham */
2897 0xABF0, /* Meetei Mayek */
2898 0xff10, /* Pliene chasse (?) */
2899 0xffff /* Terminator */
2901 /* Digits which are represented, but out of sequence */
2902 static const WCHAR outOfSequenceDigits[] =
2904 0xB9, /* Superscript 1 */
2905 0xB2, /* Superscript 2 */
2906 0xB3, /* Superscript 3 */
2907 0x0C78, /* Telugu Fraction 0 */
2908 0x0C79, /* Telugu Fraction 1 */
2909 0x0C7A, /* Telugu Fraction 2 */
2910 0x0C7B, /* Telugu Fraction 3 */
2911 0x0C7C, /* Telugu Fraction 1 */
2912 0x0C7D, /* Telugu Fraction 2 */
2913 0x0C7E, /* Telugu Fraction 3 */
2914 0x0F33, /* Tibetan half zero */
2915 0x19DA, /* New Tai Lue Tham 1 */
2916 0x24EA, /* Circled 0 */
2917 0x24FF, /* Negative Circled 0 */
2918 0x3007, /* Ideographic number zero */
2919 '\0' /* Terminator */
2921 /* Digits in digitRanges for which no representation is available */
2922 static const WCHAR noDigitAvailable[] =
2924 0x0BE6, /* No Tamil 0 */
2925 0x0F29, /* No Tibetan half zero (out of sequence) */
2926 0x1368, /* No Ethiopic 0 */
2927 0x2473, /* No Bracketed 0 */
2928 0x2487, /* No 0 Full stop */
2929 0x24F4, /* No double circled 0 */
2930 0x2775, /* No inverted circled 0 */
2931 0x277F, /* No patterned circled */
2932 0x2789, /* No inverted Patterned circled */
2933 0x3020, /* No Hangzhou 0 */
2934 '\0' /* Terminator */
2936 static const WCHAR foldczone_src[] =
2938 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2939 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2941 static const WCHAR foldczone_dst[] =
2943 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2945 static const WCHAR foldczone_todo_src[] =
2947 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2949 static const WCHAR foldczone_todo_dst[] =
2951 0x3cb,0x1f0,' ','a',0
2953 static const WCHAR foldczone_todo_broken_dst[] =
2955 0x3cb,0x1f0,0xa0,0xaa,0
2957 static const WCHAR ligatures_src[] =
2959 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2960 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2961 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2962 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2963 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2964 0xfb04, 0xfb05, 0xfb06, '\0'
2966 static const WCHAR ligatures_dst[] =
2968 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2969 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2970 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2971 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2972 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2973 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2976 if (!pFoldStringW)
2978 win_skip("FoldStringW is not available\n");
2979 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2982 /* Invalid flag combinations */
2983 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2985 src[0] = dst[0] = '\0';
2986 SetLastError(0);
2987 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2988 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2990 win_skip("FoldStringW is not implemented\n");
2991 return;
2993 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2994 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2997 /* src & dst cannot be the same */
2998 SetLastError(0);
2999 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3000 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3001 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3003 /* src can't be NULL */
3004 SetLastError(0);
3005 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3006 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3007 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3009 /* srclen can't be 0 */
3010 SetLastError(0);
3011 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3012 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3013 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3015 /* dstlen can't be < 0 */
3016 SetLastError(0);
3017 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3018 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3019 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3021 /* Ret includes terminating NUL which is appended if srclen = -1 */
3022 SetLastError(0);
3023 src[0] = 'A';
3024 src[1] = '\0';
3025 dst[0] = '\0';
3026 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3027 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3028 ok(dst[0] == 'A' && dst[1] == '\0',
3029 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3030 'A', '\0', ret, dst[0], dst[1], GetLastError());
3032 /* If size is given, result is not NUL terminated */
3033 SetLastError(0);
3034 src[0] = 'A';
3035 src[1] = 'A';
3036 dst[0] = 'X';
3037 dst[1] = 'X';
3038 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3039 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3040 ok(dst[0] == 'A' && dst[1] == 'X',
3041 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3042 'A','X', ret, dst[0], dst[1], GetLastError());
3044 /* MAP_FOLDDIGITS */
3045 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3047 /* Check everything before this range */
3048 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3050 SetLastError(0);
3051 src[0] = ch;
3052 src[1] = dst[0] = '\0';
3053 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3054 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3056 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3057 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3058 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3059 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3060 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3061 "char %04x should not be a digit\n", ch );
3064 if (digitRanges[j] == 0xffff)
3065 break; /* Finished the whole code point space */
3067 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3069 WCHAR c;
3071 /* Map out of sequence characters */
3072 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3073 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3074 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3075 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3076 else c = ch;
3077 SetLastError(0);
3078 src[0] = c;
3079 src[1] = dst[0] = '\0';
3080 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3081 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3083 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3084 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3085 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3086 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3087 strchrW(noDigitAvailable, c),
3088 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3089 ch, '0' + digitRanges[j] - ch, dst[0]);
3091 prev_ch = ch;
3094 /* MAP_FOLDCZONE */
3095 SetLastError(0);
3096 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3097 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3098 "Got %d, error %d\n", ret, GetLastError());
3099 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3100 "MAP_FOLDCZONE: Expanded incorrectly\n");
3102 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3103 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3104 "Got %d, error %d\n", ret, GetLastError());
3105 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3106 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3107 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3109 /* MAP_EXPAND_LIGATURES */
3110 SetLastError(0);
3111 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3112 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3113 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3114 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3115 "Got %d, error %d\n", ret, GetLastError());
3116 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3117 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3120 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3125 #define LCID_OK(l) \
3126 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3127 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3128 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3129 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3130 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3132 static void test_ConvertDefaultLocale(void)
3134 LCID lcid;
3136 /* Doesn't change lcid, even if non default sublang/sort used */
3137 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3138 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3139 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3140 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3142 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3143 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3144 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3145 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3146 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3148 /* Invariant language is not treated specially */
3149 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3151 /* User/system default languages alone are not mapped */
3152 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3153 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3155 /* Default lcids */
3156 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3157 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3158 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3159 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3160 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3161 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3164 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3165 DWORD dwFlags, LONG_PTR lParam)
3167 if (winetest_debug > 1)
3168 trace("%08x, %s, %s, %08x, %08lx\n",
3169 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3171 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3172 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3174 /* If lParam is one, we are calling with flags defaulted from 0 */
3175 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3176 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3178 return TRUE;
3181 static void test_EnumSystemLanguageGroupsA(void)
3183 BOOL ret;
3185 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3187 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3188 return;
3191 /* No enumeration proc */
3192 SetLastError(0);
3193 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3194 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3196 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3197 return;
3199 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3200 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3202 /* Invalid flags */
3203 SetLastError(0);
3204 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3205 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3207 /* No flags - defaults to LGRPID_INSTALLED */
3208 SetLastError(0xdeadbeef);
3209 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3210 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3212 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3213 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3216 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3218 if (winetest_debug > 1)
3219 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3220 return TRUE;
3223 static void test_EnumSystemLocalesEx(void)
3225 BOOL ret;
3227 if (!pEnumSystemLocalesEx)
3229 win_skip( "EnumSystemLocalesEx not available\n" );
3230 return;
3232 SetLastError( 0xdeadbeef );
3233 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3234 ok( !ret, "should have failed\n" );
3235 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3236 SetLastError( 0xdeadbeef );
3237 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3238 ok( ret, "failed err %u\n", GetLastError() );
3241 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3242 LONG_PTR lParam)
3244 if (winetest_debug > 1)
3245 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3247 /* invalid locale enumerated on some platforms */
3248 if (lcid == 0)
3249 return TRUE;
3251 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3252 "Enumerated grp %d not valid\n", lgrpid);
3253 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3254 "Enumerated grp locale %04x not valid\n", lcid);
3255 return TRUE;
3258 static void test_EnumLanguageGroupLocalesA(void)
3260 BOOL ret;
3262 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3264 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3265 return;
3268 /* No enumeration proc */
3269 SetLastError(0);
3270 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3271 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3273 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3274 return;
3276 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3277 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3279 /* lgrpid too small */
3280 SetLastError(0);
3281 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3282 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3283 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3285 /* lgrpid too big */
3286 SetLastError(0);
3287 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3288 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3289 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3291 /* dwFlags is reserved */
3292 SetLastError(0);
3293 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3294 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3295 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3297 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3300 static void test_SetLocaleInfoA(void)
3302 BOOL bRet;
3303 LCID lcid = GetUserDefaultLCID();
3305 /* Null data */
3306 SetLastError(0);
3307 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3308 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3309 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3311 /* IDATE */
3312 SetLastError(0);
3313 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3314 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3315 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3317 /* ILDATE */
3318 SetLastError(0);
3319 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3320 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3321 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3324 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3326 if (winetest_debug > 1)
3327 trace("%s %08lx\n", value, lParam);
3328 return(TRUE);
3331 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3333 ok(!enumCount, "callback called again unexpected\n");
3334 enumCount++;
3335 return(FALSE);
3338 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3340 ok(0,"callback called unexpected\n");
3341 return(FALSE);
3344 static void test_EnumUILanguageA(void)
3346 BOOL ret;
3347 if (!pEnumUILanguagesA) {
3348 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3349 return;
3352 SetLastError(ERROR_SUCCESS);
3353 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3354 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3356 win_skip("EnumUILanguagesA is not implemented\n");
3357 return;
3359 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3361 enumCount = 0;
3362 SetLastError(ERROR_SUCCESS);
3363 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3364 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3366 SetLastError(ERROR_SUCCESS);
3367 ret = pEnumUILanguagesA(NULL, 0, 0);
3368 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3369 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3370 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3372 SetLastError(ERROR_SUCCESS);
3373 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3374 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3375 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3377 SetLastError(ERROR_SUCCESS);
3378 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3379 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3380 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3381 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3384 static char date_fmt_buf[1024];
3385 static WCHAR date_fmt_bufW[1024];
3387 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3389 lstrcatA(date_fmt_buf, fmt);
3390 lstrcatA(date_fmt_buf, "\n");
3391 return TRUE;
3394 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3396 lstrcatW(date_fmt_bufW, fmt);
3397 return FALSE;
3400 static void test_EnumDateFormatsA(void)
3402 char *p, buf[256];
3403 BOOL ret;
3404 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3406 date_fmt_buf[0] = 0;
3407 SetLastError(0xdeadbeef);
3408 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3409 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3411 win_skip("0 for dwFlags is not supported\n");
3413 else
3415 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3416 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3417 /* test the 1st enumerated format */
3418 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3419 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3420 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3421 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3424 date_fmt_buf[0] = 0;
3425 SetLastError(0xdeadbeef);
3426 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3427 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3429 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3431 else
3433 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3434 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3435 /* test the 1st enumerated format */
3436 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3437 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3438 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3439 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3442 date_fmt_buf[0] = 0;
3443 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3444 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3445 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3446 /* test the 1st enumerated format */
3447 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3448 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3449 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3450 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3452 date_fmt_buf[0] = 0;
3453 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3454 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3455 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3456 /* test the 1st enumerated format */
3457 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3458 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3459 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3460 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3462 date_fmt_buf[0] = 0;
3463 SetLastError(0xdeadbeef);
3464 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3465 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3467 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3468 return;
3470 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3471 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3472 /* test the 1st enumerated format */
3473 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3474 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3475 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3476 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3477 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3480 static void test_EnumTimeFormatsA(void)
3482 char *p, buf[256];
3483 BOOL ret;
3484 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3486 date_fmt_buf[0] = 0;
3487 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3488 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3489 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3490 /* test the 1st enumerated format */
3491 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3492 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3493 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3494 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3496 date_fmt_buf[0] = 0;
3497 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3498 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3499 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3500 /* test the 1st enumerated format */
3501 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3502 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3503 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3504 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3507 static void test_EnumTimeFormatsW(void)
3509 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3510 WCHAR bufW[256];
3511 BOOL ret;
3513 date_fmt_bufW[0] = 0;
3514 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3515 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3516 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3517 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3518 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3519 wine_dbgstr_w(bufW));
3521 date_fmt_bufW[0] = 0;
3522 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3523 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3524 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3525 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3526 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3527 wine_dbgstr_w(bufW));
3529 /* TIME_NOSECONDS is Win7+ feature */
3530 date_fmt_bufW[0] = 0;
3531 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3532 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3533 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3534 else {
3535 char buf[256];
3537 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3538 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3539 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) 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 /* EnumTimeFormatsA doesn't support this flag */
3544 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3545 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3546 GetLastError());
3548 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3549 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3550 GetLastError());
3552 /* And it's not supported by GetLocaleInfoA either */
3553 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3554 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3555 GetLastError());
3558 static void test_GetCPInfo(void)
3560 BOOL ret;
3561 CPINFO cpinfo;
3563 SetLastError(0xdeadbeef);
3564 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3565 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3566 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3567 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3569 SetLastError(0xdeadbeef);
3570 ret = GetCPInfo(CP_UTF7, &cpinfo);
3571 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3573 win_skip("Codepage CP_UTF7 is not installed/available\n");
3575 else
3577 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3578 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3579 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3580 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3581 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3582 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3585 SetLastError(0xdeadbeef);
3586 ret = GetCPInfo(CP_UTF8, &cpinfo);
3587 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3589 win_skip("Codepage CP_UTF8 is not installed/available\n");
3591 else
3593 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3594 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3595 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3596 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3597 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3598 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3599 "expected 4, got %u\n", cpinfo.MaxCharSize);
3604 * The CT_TYPE1 has varied over windows version.
3605 * The current target for correct behavior is windows 7.
3606 * There was a big shift between windows 2000 (first introduced) and windows Xp
3607 * Most of the old values below are from windows 2000.
3608 * A smaller subset of changes happened between windows Xp and Window vista/7
3610 static void test_GetStringTypeW(void)
3612 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3613 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3614 C1_SPACE | C1_BLANK | C1_DEFINED,
3615 C1_SPACE | C1_BLANK | C1_DEFINED,
3616 C1_SPACE | C1_BLANK | C1_DEFINED,
3617 C1_CNTRL | C1_BLANK | C1_DEFINED};
3618 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3619 C1_SPACE | C1_BLANK,
3620 C1_SPACE | C1_BLANK,
3621 C1_SPACE | C1_BLANK,
3622 C1_SPACE | C1_BLANK};
3624 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3626 /* Lu, Ll, Lt */
3627 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3628 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3629 C1_LOWER | C1_ALPHA,
3630 C1_UPPER | C1_LOWER | C1_ALPHA,
3631 C1_ALPHA};
3633 /* Sk, Sk, Mn, So, Me */
3634 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3635 /* Sc, Sm, No,*/
3636 0xffe0, 0xffe9, 0x2153};
3638 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3639 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3640 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3641 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3642 C1_ALPHA | C1_DEFINED,
3643 C1_CNTRL | C1_DEFINED,
3644 C1_PUNCT | C1_DEFINED,
3645 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3646 C1_ALPHA | C1_LOWER | C1_DEFINED,
3647 C1_ALPHA | C1_DEFINED };
3648 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3649 C1_ALPHA | C1_DEFINED,
3650 C1_CNTRL | C1_DEFINED,
3651 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3652 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3653 C1_ALPHA | C1_DEFINED,
3654 C1_DEFINED
3656 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3657 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3659 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3660 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3661 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3662 static const WCHAR lower_special[] = {0x2071, 0x207f};
3663 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3664 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3665 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3666 0xfff9, 0xfffa, 0xfffb};
3667 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3669 WORD types[20];
3670 WCHAR ch[2];
3671 BOOL ret;
3672 int i;
3674 /* NULL src */
3675 SetLastError(0xdeadbeef);
3676 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3677 ok(!ret, "got %d\n", ret);
3678 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3680 SetLastError(0xdeadbeef);
3681 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3682 ok(!ret, "got %d\n", ret);
3683 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3685 SetLastError(0xdeadbeef);
3686 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3687 ok(!ret, "got %d\n", ret);
3688 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3690 memset(types,0,sizeof(types));
3691 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3692 for (i = 0; i < 5; i++)
3693 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]);
3695 memset(types,0,sizeof(types));
3696 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3697 for (i = 0; i < 3; i++)
3698 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]));
3699 memset(types,0,sizeof(types));
3700 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3701 for (i = 0; i < 5; i++)
3702 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3704 memset(types,0,sizeof(types));
3705 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3706 for (i = 0; i < 8; i++)
3707 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);
3709 memset(types,0,sizeof(types));
3710 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3711 for (i = 0; i < 7; i++)
3712 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]);
3714 memset(types,0,sizeof(types));
3715 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3716 for (i = 0; i < 7; i++)
3717 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));
3720 memset(types,0,sizeof(types));
3721 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3722 for (i = 0; i < 12; i++)
3723 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);
3725 memset(types,0,sizeof(types));
3726 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3727 for (i = 0; i < 3; i++)
3728 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);
3730 memset(types,0,sizeof(types));
3731 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3732 for (i = 0; i < 2; i++)
3733 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);
3735 memset(types,0,sizeof(types));
3736 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3737 for (i = 0; i < 20; i++)
3738 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);
3740 memset(types,0,sizeof(types));
3741 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3742 for (i = 0; i < 3; i++)
3743 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 );
3745 /* surrogate pairs */
3746 ch[0] = 0xd800;
3747 memset(types, 0, sizeof(types));
3748 GetStringTypeW(CT_CTYPE3, ch, 1, types);
3749 if (types[0] == C3_NOTAPPLICABLE)
3750 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
3751 else {
3752 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
3754 ch[0] = 0xdc00;
3755 memset(types, 0, sizeof(types));
3756 GetStringTypeW(CT_CTYPE3, ch, 1, types);
3757 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
3760 /* Zl, Zp categories */
3761 ch[0] = 0x2028;
3762 ch[1] = 0x2029;
3763 memset(types, 0, sizeof(types));
3764 GetStringTypeW(CT_CTYPE1, ch, 2, types);
3765 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
3766 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
3769 static void test_IdnToNameprepUnicode(void)
3771 struct {
3772 DWORD in_len;
3773 const WCHAR in[64];
3774 DWORD ret;
3775 DWORD broken_ret;
3776 const WCHAR out[64];
3777 DWORD flags;
3778 DWORD err;
3779 DWORD todo;
3780 } test_data[] = {
3782 5, {'t','e','s','t',0},
3783 5, 5, {'t','e','s','t',0},
3784 0, 0xdeadbeef
3787 3, {'a',0xe111,'b'},
3788 0, 0, {0},
3789 0, ERROR_INVALID_NAME
3792 4, {'t',0,'e',0},
3793 0, 0, {0},
3794 0, ERROR_INVALID_NAME
3797 1, {'T',0},
3798 1, 1, {'T',0},
3799 0, 0xdeadbeef
3802 1, {0},
3803 0, 0, {0},
3804 0, ERROR_INVALID_NAME
3807 6, {' ','-','/','[',']',0},
3808 6, 6, {' ','-','/','[',']',0},
3809 0, 0xdeadbeef
3812 3, {'a','-','a'},
3813 3, 3, {'a','-','a'},
3814 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3817 3, {'a','a','-'},
3818 0, 0, {0},
3819 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3821 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3822 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3823 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3824 0, 0xdeadbeef, TRUE
3827 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3828 2, 0, {'t',0},
3829 0, 0xdeadbeef
3831 { /* Another example of incorrectly working FoldString (composition) */
3832 2, {0x3b0, 0},
3833 2, 2, {0x3b0, 0},
3834 0, 0xdeadbeef, TRUE
3837 2, {0x221, 0},
3838 0, 2, {0},
3839 0, ERROR_NO_UNICODE_TRANSLATION
3842 2, {0x221, 0},
3843 2, 2, {0x221, 0},
3844 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3847 5, {'a','.','.','a',0},
3848 0, 0, {0},
3849 0, ERROR_INVALID_NAME
3852 3, {'a','.',0},
3853 3, 3, {'a','.',0},
3854 0, 0xdeadbeef
3858 WCHAR buf[1024];
3859 DWORD i, ret, err;
3861 if (!pIdnToNameprepUnicode)
3863 win_skip("IdnToNameprepUnicode is not available\n");
3864 return;
3867 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3868 test_data[0].in_len, NULL, 0);
3869 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3871 SetLastError(0xdeadbeef);
3872 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3873 test_data[1].in_len, NULL, 0);
3874 err = GetLastError();
3875 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3876 ok(err == test_data[1].err, "err = %d\n", err);
3878 SetLastError(0xdeadbeef);
3879 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3880 buf, sizeof(buf)/sizeof(WCHAR));
3881 err = GetLastError();
3882 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3883 ok(err == 0xdeadbeef, "err = %d\n", err);
3885 SetLastError(0xdeadbeef);
3886 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3887 buf, sizeof(buf)/sizeof(WCHAR));
3888 err = GetLastError();
3889 ok(ret == 0, "ret = %d\n", ret);
3890 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3892 SetLastError(0xdeadbeef);
3893 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3894 buf, sizeof(buf)/sizeof(WCHAR));
3895 err = GetLastError();
3896 ok(ret == 0, "ret = %d\n", ret);
3897 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3899 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3900 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3901 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3903 SetLastError(0xdeadbeef);
3904 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3905 err = GetLastError();
3906 ok(ret == 0, "ret = %d\n", ret);
3907 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3909 SetLastError(0xdeadbeef);
3910 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3911 err = GetLastError();
3912 ok(ret == 0, "ret = %d\n", ret);
3913 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
3914 "err = %d\n", err);
3916 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3918 SetLastError(0xdeadbeef);
3919 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3920 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3921 err = GetLastError();
3923 todo_wine_if (test_data[i].todo)
3924 ok(ret == test_data[i].ret ||
3925 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3927 if(ret != test_data[i].ret)
3928 continue;
3930 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3931 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3932 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3936 static void test_IdnToAscii(void)
3938 struct {
3939 DWORD in_len;
3940 const WCHAR in[64];
3941 DWORD ret;
3942 const WCHAR out[64];
3943 DWORD flags;
3944 DWORD err;
3945 } test_data[] = {
3947 5, {'T','e','s','t',0},
3948 5, {'T','e','s','t',0},
3949 0, 0xdeadbeef
3952 5, {'T','e',0x017c,'s','t',0},
3953 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3954 0, 0xdeadbeef
3957 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3958 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3959 0, 0xdeadbeef
3962 3, {0x0105,'.',0},
3963 9, {'x','n','-','-','2','d','a','.',0},
3964 0, 0xdeadbeef
3967 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3968 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3969 0, 0xdeadbeef
3972 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3973 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3974 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3975 0, 0xdeadbeef
3978 2, {0x221,0},
3979 8, {'x','n','-','-','6','l','a',0},
3980 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3984 WCHAR buf[1024];
3985 DWORD i, ret, err;
3987 if (!pIdnToAscii)
3989 win_skip("IdnToAscii is not available\n");
3990 return;
3993 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3995 SetLastError(0xdeadbeef);
3996 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3997 test_data[i].in_len, buf, sizeof(buf));
3998 err = GetLastError();
3999 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4000 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4001 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4002 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4006 static void test_IdnToUnicode(void)
4008 struct {
4009 DWORD in_len;
4010 const WCHAR in[64];
4011 DWORD ret;
4012 const WCHAR out[64];
4013 DWORD flags;
4014 DWORD err;
4015 } test_data[] = {
4017 5, {'T','e','s','.',0},
4018 5, {'T','e','s','.',0},
4019 0, 0xdeadbeef
4022 2, {0x105,0},
4023 0, {0},
4024 0, ERROR_INVALID_NAME
4027 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4028 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4029 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4030 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4031 0x05d1,0x05e8,0x05d9,0x05ea,0},
4032 0, 0xdeadbeef
4035 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4036 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4037 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4038 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4039 0, 0xdeadbeef
4042 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4043 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4044 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4045 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4046 0, {0},
4047 0, ERROR_INVALID_NAME
4050 8, {'x','n','-','-','6','l','a',0},
4051 2, {0x221,0},
4052 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4056 WCHAR buf[1024];
4057 DWORD i, ret, err;
4059 if (!pIdnToUnicode)
4061 win_skip("IdnToUnicode is not available\n");
4062 return;
4065 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4067 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4068 test_data[i].in_len, NULL, 0);
4069 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4071 SetLastError(0xdeadbeef);
4072 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4073 test_data[i].in_len, buf, sizeof(buf));
4074 err = GetLastError();
4075 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4076 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4077 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4078 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4082 static void test_GetLocaleInfoEx(void)
4084 static const WCHAR enW[] = {'e','n',0};
4085 WCHAR bufferW[80];
4086 INT ret;
4088 if (!pGetLocaleInfoEx)
4090 win_skip("GetLocaleInfoEx not supported\n");
4091 return;
4094 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4095 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4096 if (ret)
4098 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4099 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4100 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4101 static const WCHAR usaW[] = {'U','S','A',0};
4102 static const WCHAR enuW[] = {'E','N','U',0};
4103 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4104 DWORD val;
4106 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4107 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4109 SetLastError(0xdeadbeef);
4110 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4111 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4113 SetLastError(0xdeadbeef);
4114 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4115 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4117 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4118 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4119 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4121 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4122 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4123 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4125 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4126 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4127 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4129 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4130 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4131 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4132 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4134 skip("Non-English locale\n");
4136 else
4137 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4139 bufferW[0] = 0;
4140 SetLastError(0xdeadbeef);
4141 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4142 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4144 while (*ptr->name)
4146 val = 0;
4147 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4148 todo_wine_if (ptr->todo)
4149 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4150 bufferW[0] = 0;
4151 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4152 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4153 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4154 ptr++;
4159 static void test_IsValidLocaleName(void)
4161 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4162 static const WCHAR zzW[] = {'z','z',0};
4163 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4164 BOOL ret;
4166 if (!pIsValidLocaleName)
4168 win_skip("IsValidLocaleName not supported\n");
4169 return;
4172 ret = pIsValidLocaleName(enusW);
4173 ok(ret, "IsValidLocaleName failed\n");
4174 ret = pIsValidLocaleName(zzW);
4175 ok(!ret, "IsValidLocaleName should have failed\n");
4176 ret = pIsValidLocaleName(zzzzW);
4177 ok(!ret, "IsValidLocaleName should have failed\n");
4178 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4179 ok(ret, "IsValidLocaleName failed\n");
4182 static void test_CompareStringOrdinal(void)
4184 INT ret;
4185 WCHAR test1[] = { 't','e','s','t',0 };
4186 WCHAR test2[] = { 'T','e','S','t',0 };
4187 WCHAR test3[] = { 't','e','s','t','3',0 };
4188 WCHAR null1[] = { 'a',0,'a',0 };
4189 WCHAR null2[] = { 'a',0,'b',0 };
4190 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4191 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4192 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4193 WCHAR coop2[] = { 'c','o','o','p',0 };
4194 WCHAR nonascii1[] = { 0x0102,0 };
4195 WCHAR nonascii2[] = { 0x0201,0 };
4197 if (!pCompareStringOrdinal)
4199 win_skip("CompareStringOrdinal not supported\n");
4200 return;
4203 /* Check errors */
4204 SetLastError(0xdeadbeef);
4205 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4206 ok(!ret, "Got %u, expected 0\n", ret);
4207 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4208 SetLastError(0xdeadbeef);
4209 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4210 ok(!ret, "Got %u, expected 0\n", ret);
4211 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4212 SetLastError(0xdeadbeef);
4213 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4214 ok(!ret, "Got %u, expected 0\n", ret);
4215 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4217 /* Check case */
4218 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4219 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4220 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4221 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4222 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4223 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4224 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4225 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4227 /* Check different sizes */
4228 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4229 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4230 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4231 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4233 /* Check null character */
4234 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4235 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4236 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4237 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4238 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4239 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4240 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4241 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4243 /* Check ordinal behaviour */
4244 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4245 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4246 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4247 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4248 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4249 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4250 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4251 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4254 static void test_GetGeoInfo(void)
4256 char buffA[20];
4257 INT ret;
4259 if (!pGetGeoInfoA)
4261 win_skip("GetGeoInfo is not available.\n");
4262 return;
4265 /* unassigned id */
4266 SetLastError(0xdeadbeef);
4267 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4268 ok(ret == 0, "got %d\n", ret);
4269 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4271 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4272 ok(ret == 3, "got %d\n", ret);
4274 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4275 ok(ret == 4, "got %d\n", ret);
4277 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4278 ok(ret == 3, "got %d\n", ret);
4279 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4281 /* buffer pointer not NULL, length is 0 - return required length */
4282 buffA[0] = 'a';
4283 SetLastError(0xdeadbeef);
4284 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4285 ok(ret == 3, "got %d\n", ret);
4286 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4288 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4289 ok(ret == 4, "got %d\n", ret);
4290 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4292 /* shorter buffer */
4293 SetLastError(0xdeadbeef);
4294 buffA[1] = buffA[2] = 0;
4295 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4296 ok(ret == 0, "got %d\n", ret);
4297 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4298 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4300 /* GEO_NATION returns GEOID in a string form */
4301 buffA[0] = 0;
4302 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4303 ok(ret == 4, "got %d\n", ret);
4304 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4306 /* GEO_PARENT */
4307 buffA[0] = 0;
4308 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4309 if (ret == 0)
4310 win_skip("GEO_PARENT not supported.\n");
4311 else
4313 ok(ret == 6, "got %d\n", ret);
4314 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4317 buffA[0] = 0;
4318 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4319 if (ret == 0)
4320 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4321 else
4323 ok(ret == 4, "got %d\n", ret);
4324 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4327 /* try invalid type value */
4328 SetLastError(0xdeadbeef);
4329 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4330 ok(ret == 0, "got %d\n", ret);
4331 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4334 static int geoidenum_count;
4335 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4337 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4338 ok(ret == 3, "got %d for %d\n", ret, geoid);
4339 /* valid geoid starts at 2 */
4340 ok(geoid >= 2, "got geoid %d\n", geoid);
4342 return geoidenum_count++ < 5;
4345 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4347 geoidenum_count++;
4348 return TRUE;
4351 static void test_EnumSystemGeoID(void)
4353 BOOL ret;
4355 if (!pEnumSystemGeoID)
4357 win_skip("EnumSystemGeoID is not available.\n");
4358 return;
4361 SetLastError(0xdeadbeef);
4362 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4363 ok(!ret, "got %d\n", ret);
4364 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4366 SetLastError(0xdeadbeef);
4367 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4368 ok(!ret, "got %d\n", ret);
4369 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4371 SetLastError(0xdeadbeef);
4372 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4373 ok(!ret, "got %d\n", ret);
4374 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4376 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4377 ok(ret, "got %d\n", ret);
4379 /* only the first level is enumerated, not the whole hierarchy */
4380 geoidenum_count = 0;
4381 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4382 if (ret == 0)
4383 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4384 else
4385 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4387 geoidenum_count = 0;
4388 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4389 if (ret == 0)
4390 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4391 else
4393 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4395 geoidenum_count = 0;
4396 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4397 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4401 struct invariant_entry {
4402 const char *name;
4403 int id;
4404 const char *expect;
4407 #define X(x) #x, x
4408 static const struct invariant_entry invariant_list[] = {
4409 { X(LOCALE_ILANGUAGE), "007f" },
4410 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4411 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4412 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4413 { X(LOCALE_ICOUNTRY), "1" },
4414 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4415 { X(LOCALE_SABBREVCTRYNAME), "IVC" },
4416 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4417 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4418 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4419 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4420 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4421 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4422 { X(LOCALE_SLIST), "," },
4423 { X(LOCALE_IMEASURE), "0" },
4424 { X(LOCALE_SDECIMAL), "." },
4425 { X(LOCALE_STHOUSAND), "," },
4426 { X(LOCALE_SGROUPING), "3;0" },
4427 { X(LOCALE_IDIGITS), "2" },
4428 { X(LOCALE_ILZERO), "1" },
4429 { X(LOCALE_INEGNUMBER), "1" },
4430 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4431 { X(LOCALE_SCURRENCY), "\x00a4" },
4432 { X(LOCALE_SINTLSYMBOL), "XDR" },
4433 { X(LOCALE_SMONDECIMALSEP), "." },
4434 { X(LOCALE_SMONTHOUSANDSEP), "," },
4435 { X(LOCALE_SMONGROUPING), "3;0" },
4436 { X(LOCALE_ICURRDIGITS), "2" },
4437 { X(LOCALE_IINTLCURRDIGITS), "2" },
4438 { X(LOCALE_ICURRENCY), "0" },
4439 { X(LOCALE_INEGCURR), "0" },
4440 { X(LOCALE_SDATE), "/" },
4441 { X(LOCALE_STIME), ":" },
4442 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4443 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4444 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4445 { X(LOCALE_IDATE), "0" },
4446 { X(LOCALE_ILDATE), "1" },
4447 { X(LOCALE_ITIME), "1" },
4448 { X(LOCALE_ITIMEMARKPOSN), "0" },
4449 { X(LOCALE_ICENTURY), "1" },
4450 { X(LOCALE_ITLZERO), "1" },
4451 { X(LOCALE_IDAYLZERO), "1" },
4452 { X(LOCALE_IMONLZERO), "1" },
4453 { X(LOCALE_S1159), "AM" },
4454 { X(LOCALE_S2359), "PM" },
4455 { X(LOCALE_ICALENDARTYPE), "1" },
4456 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4457 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4458 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4459 { X(LOCALE_SDAYNAME1), "Monday" },
4460 { X(LOCALE_SDAYNAME2), "Tuesday" },
4461 { X(LOCALE_SDAYNAME3), "Wednesday" },
4462 { X(LOCALE_SDAYNAME4), "Thursday" },
4463 { X(LOCALE_SDAYNAME5), "Friday" },
4464 { X(LOCALE_SDAYNAME6), "Saturday" },
4465 { X(LOCALE_SDAYNAME7), "Sunday" },
4466 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4467 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4468 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4469 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4470 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4471 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4472 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4473 { X(LOCALE_SMONTHNAME1), "January" },
4474 { X(LOCALE_SMONTHNAME2), "February" },
4475 { X(LOCALE_SMONTHNAME3), "March" },
4476 { X(LOCALE_SMONTHNAME4), "April" },
4477 { X(LOCALE_SMONTHNAME5), "May" },
4478 { X(LOCALE_SMONTHNAME6), "June" },
4479 { X(LOCALE_SMONTHNAME7), "July" },
4480 { X(LOCALE_SMONTHNAME8), "August" },
4481 { X(LOCALE_SMONTHNAME9), "September" },
4482 { X(LOCALE_SMONTHNAME10), "October" },
4483 { X(LOCALE_SMONTHNAME11), "November" },
4484 { X(LOCALE_SMONTHNAME12), "December" },
4485 { X(LOCALE_SMONTHNAME13), "" },
4486 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4487 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4488 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4489 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4490 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4491 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4492 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4493 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4494 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4495 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4496 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4497 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4498 { X(LOCALE_SABBREVMONTHNAME13), "" },
4499 { X(LOCALE_SPOSITIVESIGN), "+" },
4500 { X(LOCALE_SNEGATIVESIGN), "-" },
4501 { X(LOCALE_IPOSSIGNPOSN), "3" },
4502 { X(LOCALE_INEGSIGNPOSN), "0" },
4503 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4504 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4505 { X(LOCALE_INEGSYMPRECEDES), "1" },
4506 { X(LOCALE_INEGSEPBYSPACE), "0" },
4507 { X(LOCALE_SISO639LANGNAME), "iv" },
4508 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4509 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4510 { X(LOCALE_IPAPERSIZE), "9" },
4511 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4512 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4513 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4514 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4515 { X(LOCALE_SNAME), "" },
4516 { X(LOCALE_SSCRIPTS), "Latn;" },
4517 { 0 }
4519 #undef X
4521 static void test_invariant(void)
4523 int ret;
4524 int len;
4525 char buffer[BUFFER_SIZE];
4526 const struct invariant_entry *ptr = invariant_list;
4528 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4530 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4531 return;
4534 while (ptr->name)
4536 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4537 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4538 win_skip("not supported\n"); /* winxp/win2k3 */
4539 else
4541 len = strlen(ptr->expect)+1; /* include \0 */
4542 ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
4543 ptr->id, len, ret, GetLastError());
4544 ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
4545 ptr->id, ptr->expect, buffer);
4548 ptr++;
4551 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4552 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4554 skip("Non-English locale\n");
4556 else
4558 /* some locales translate these */
4559 static const char lang[] = "Invariant Language (Invariant Country)";
4560 static const char cntry[] = "Invariant Country";
4561 static const char sortm[] = "Math Alphanumerics";
4562 static const char sortd[] = "Default"; /* win2k3 */
4564 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4565 len = lstrlenA(lang) + 1;
4566 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4567 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4569 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4570 len = lstrlenA(cntry) + 1;
4571 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4572 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4574 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4575 if (ret == lstrlenA(sortm)+1)
4576 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4577 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4578 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4579 else
4580 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4581 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4585 static void test_GetSystemPreferredUILanguages(void)
4587 BOOL ret;
4588 ULONG count, size, size_id, size_name, size_buffer;
4589 WCHAR *buffer;
4592 if (!pGetSystemPreferredUILanguages)
4594 win_skip("GetSystemPreferredUILanguages is not available.\n");
4595 return;
4598 /* (in)valid first parameter */
4599 count = 0xdeadbeef;
4600 size = 0;
4601 SetLastError(0xdeadbeef);
4602 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4603 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4604 ok(count, "Expected count > 0\n");
4605 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4607 count = 0xdeadbeef;
4608 size = 0;
4609 SetLastError(0xdeadbeef);
4610 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4611 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4612 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4613 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4615 count = 0xdeadbeef;
4616 size = 0;
4617 SetLastError(0xdeadbeef);
4618 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4619 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4620 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4621 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4623 count = 0xdeadbeef;
4624 size = 0;
4625 SetLastError(0xdeadbeef);
4626 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
4627 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4628 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4629 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4631 count = 0xdeadbeef;
4632 size = 0;
4633 SetLastError(0xdeadbeef);
4634 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4635 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4636 ok(count, "Expected count > 0\n");
4637 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4639 count = 0xdeadbeef;
4640 size = 0;
4641 SetLastError(0xdeadbeef);
4642 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4643 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4644 ok(count, "Expected count > 0\n");
4645 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4647 /* second parameter
4648 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
4649 * -> unhandled exception c0000005
4652 /* invalid third parameter */
4653 count = 0xdeadbeef;
4654 size = 1;
4655 SetLastError(0xdeadbeef);
4656 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
4657 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4658 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4659 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4661 /* fourth parameter
4662 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
4663 * -> unhandled exception c0000005
4666 count = 0xdeadbeef;
4667 size_id = 0;
4668 SetLastError(0xdeadbeef);
4669 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
4670 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4671 ok(count, "Expected count > 0\n");
4672 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
4674 count = 0xdeadbeef;
4675 size_name = 0;
4676 SetLastError(0xdeadbeef);
4677 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
4678 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4679 ok(count, "Expected count > 0\n");
4680 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
4682 size_buffer = max(size_id, size_name);
4683 if(!size_buffer)
4685 skip("No vaild buffer size\n");
4686 return;
4689 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
4690 if (!buffer)
4692 skip("Failed to allocate memory for %d chars\n", size_buffer);
4693 return;
4696 count = 0xdeadbeef;
4697 size = size_buffer;
4698 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4699 SetLastError(0xdeadbeef);
4700 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4701 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4702 ok(count, "Expected count > 0\n");
4703 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4704 if (ret && size % 6 == 1)
4705 ok(!buffer[size -2] && !buffer[size -1],
4706 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4707 buffer[size -2], buffer[size -1]);
4709 count = 0xdeadbeef;
4710 size = size_buffer;
4711 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4712 SetLastError(0xdeadbeef);
4713 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4714 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4715 ok(count, "Expected count > 0\n");
4716 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4717 if (ret && size % 5 == 1)
4718 ok(!buffer[size -2] && !buffer[size -1],
4719 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4720 buffer[size -2], buffer[size -1]);
4722 count = 0xdeadbeef;
4723 size = size_buffer;
4724 SetLastError(0xdeadbeef);
4725 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
4726 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4727 ok(count, "Expected count > 0\n");
4728 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4729 if (ret && size % 5 == 1)
4730 ok(!buffer[size -2] && !buffer[size -1],
4731 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4732 buffer[size -2], buffer[size -1]);
4734 count = 0xdeadbeef;
4735 size = 0;
4736 SetLastError(0xdeadbeef);
4737 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4738 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4739 ok(count, "Expected count > 0\n");
4740 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4741 if (ret && size % 6 == 1)
4742 ok(!buffer[size -2] && !buffer[size -1],
4743 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
4744 buffer[size -2], buffer[size -1]);
4746 count = 0xdeadbeef;
4747 size = 1;
4748 SetLastError(0xdeadbeef);
4749 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4750 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4751 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4752 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4754 count = 0xdeadbeef;
4755 size = size_id -1;
4756 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4757 SetLastError(0xdeadbeef);
4758 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
4759 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4760 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4761 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4763 count = 0xdeadbeef;
4764 size = size_id -2;
4765 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
4766 SetLastError(0xdeadbeef);
4767 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
4768 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4769 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
4770 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
4773 START_TEST(locale)
4775 InitFunctionPointers();
4777 test_EnumTimeFormatsA();
4778 test_EnumTimeFormatsW();
4779 test_EnumDateFormatsA();
4780 test_GetLocaleInfoA();
4781 test_GetLocaleInfoW();
4782 test_GetLocaleInfoEx();
4783 test_GetTimeFormatA();
4784 test_GetTimeFormatEx();
4785 test_GetDateFormatA();
4786 test_GetDateFormatEx();
4787 test_GetDateFormatW();
4788 test_GetCurrencyFormatA(); /* Also tests the W version */
4789 test_GetNumberFormatA(); /* Also tests the W version */
4790 test_CompareStringA();
4791 test_CompareStringW();
4792 test_CompareStringEx();
4793 test_LCMapStringA();
4794 test_LCMapStringW();
4795 test_LCMapStringEx();
4796 test_LocaleNameToLCID();
4797 test_FoldStringA();
4798 test_FoldStringW();
4799 test_ConvertDefaultLocale();
4800 test_EnumSystemLanguageGroupsA();
4801 test_EnumSystemLocalesEx();
4802 test_EnumLanguageGroupLocalesA();
4803 test_SetLocaleInfoA();
4804 test_EnumUILanguageA();
4805 test_GetCPInfo();
4806 test_GetStringTypeW();
4807 test_IdnToNameprepUnicode();
4808 test_IdnToAscii();
4809 test_IdnToUnicode();
4810 test_IsValidLocaleName();
4811 test_CompareStringOrdinal();
4812 test_GetGeoInfo();
4813 test_EnumSystemGeoID();
4814 test_invariant();
4815 test_GetSystemPreferredUILanguages();
4816 /* this requires collation table patch to make it MS compatible */
4817 if (0) test_sorting();