kernel32: Properly implement EnumSystemGeoID().
[wine.git] / dlls / kernel32 / tests / locale.c
blob9e7f410fad30cdb2c0816d7c44dfeb2279482b4c
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 fooW[] = {'f','o','o',0};
44 static inline unsigned int strlenW( const WCHAR *str )
46 const WCHAR *s = str;
47 while (*s) s++;
48 return s - str;
51 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
53 if (n <= 0) return 0;
54 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
55 return *str1 - *str2;
58 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
60 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
61 return NULL;
64 static inline BOOL isdigitW( WCHAR wc )
66 WORD type;
67 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
68 return type & C1_DIGIT;
71 /* Some functions are only in later versions of kernel32.dll */
72 static HMODULE hKernel32;
73 static WORD enumCount;
75 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
76 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
77 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
78 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
79 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
80 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
81 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
82 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
83 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
84 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
85 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
86 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
87 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
90 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
91 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
92 LPNLSVERSIONINFO, LPVOID, LPARAM);
93 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
94 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
95 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
97 static void InitFunctionPointers(void)
99 hKernel32 = GetModuleHandleA("kernel32");
101 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
102 X(EnumSystemLanguageGroupsA);
103 X(EnumLanguageGroupLocalesA);
104 X(LocaleNameToLCID);
105 X(LCIDToLocaleName);
106 X(LCMapStringEx);
107 X(FoldStringA);
108 X(FoldStringW);
109 X(IsValidLanguageGroup);
110 X(EnumUILanguagesA);
111 X(EnumSystemLocalesEx);
112 X(IdnToNameprepUnicode);
113 X(IdnToAscii);
114 X(IdnToUnicode);
115 X(GetLocaleInfoEx);
116 X(IsValidLocaleName);
117 X(CompareStringOrdinal);
118 X(CompareStringEx);
119 X(GetGeoInfoA);
120 X(GetGeoInfoW);
121 X(EnumSystemGeoID);
122 #undef X
125 #define eq(received, expected, label, type) \
126 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
127 (label), (received), (expected))
129 #define BUFFER_SIZE 128
130 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
132 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
133 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
134 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
135 "Expected '%s', got '%s'\n", Expected, buffer)
137 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
138 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
139 SetLastError(0xdeadbeef); buffer[0] = '\0'
140 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
141 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
143 #define NUO LOCALE_NOUSEROVERRIDE
145 static void test_GetLocaleInfoA(void)
147 int ret;
148 int len;
149 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
150 char buffer[BUFFER_SIZE];
151 char expected[BUFFER_SIZE];
152 DWORD val;
154 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
156 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
157 ok(ret, "got %d\n", ret);
158 ok(val == lcid, "got 0x%08x\n", val);
160 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
161 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
162 assumes SUBLANG_NEUTRAL for zh */
163 memset(expected, 0, COUNTOF(expected));
164 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
165 SetLastError(0xdeadbeef);
166 memset(buffer, 0, COUNTOF(buffer));
167 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
168 ok((ret == len) && !lstrcmpA(buffer, expected),
169 "got %d with '%s' (expected %d with '%s')\n",
170 ret, buffer, len, expected);
172 memset(expected, 0, COUNTOF(expected));
173 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
174 if (len) {
175 SetLastError(0xdeadbeef);
176 memset(buffer, 0, COUNTOF(buffer));
177 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
178 ok((ret == len) && !lstrcmpA(buffer, expected),
179 "got %d with '%s' (expected %d with '%s')\n",
180 ret, buffer, len, expected);
182 else
183 win_skip("LANG_ARABIC not installed\n");
185 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
186 memset(expected, 0, COUNTOF(expected));
187 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
188 SetLastError(0xdeadbeef);
189 memset(buffer, 0, COUNTOF(buffer));
190 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
191 ok((ret == len) && !lstrcmpA(buffer, expected),
192 "got %d with '%s' (expected %d with '%s')\n",
193 ret, buffer, len, expected);
196 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
197 * partially fill the buffer even if it is too short. See bug 637.
199 SetLastError(0xdeadbeef);
200 memset(buffer, 0, COUNTOF(buffer));
201 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
202 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
204 SetLastError(0xdeadbeef);
205 memset(buffer, 0, COUNTOF(buffer));
206 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
207 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
208 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
209 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
211 SetLastError(0xdeadbeef);
212 memset(buffer, 0, COUNTOF(buffer));
213 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
214 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
215 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
218 struct neutralsublang_name2_t {
219 WCHAR name[3];
220 WCHAR sname[15];
221 LCID lcid;
222 LCID lcid_broken;
223 WCHAR sname_broken[15];
224 int todo;
227 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
228 { {'a','r',0}, {'a','r','-','S','A',0},
229 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
230 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
231 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
232 { {'d','e',0}, {'d','e','-','D','E',0},
233 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
234 { {'e','n',0}, {'e','n','-','U','S',0},
235 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
236 { {'e','s',0}, {'e','s','-','E','S',0},
237 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
238 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
239 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
240 { {'g','a',0}, {'g','a','-','I','E',0},
241 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
242 { {'i','t',0}, {'i','t','-','I','T',0},
243 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
244 { {'m','s',0}, {'m','s','-','M','Y',0},
245 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
246 { {'n','l',0}, {'n','l','-','N','L',0},
247 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
248 { {'p','t',0}, {'p','t','-','B','R',0},
249 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
250 { {'s','r',0}, {'h','r','-','H','R',0},
251 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
252 { {'s','v',0}, {'s','v','-','S','E',0},
253 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
254 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
255 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
256 { {'z','h',0}, {'z','h','-','C','N',0},
257 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
258 { {0} }
261 static void test_GetLocaleInfoW(void)
263 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
264 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
265 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
266 WCHAR bufferW[80], buffer2W[80];
267 CHAR bufferA[80];
268 DWORD val;
269 DWORD ret;
270 INT i;
272 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
273 if (!ret) {
274 win_skip("GetLocaleInfoW() isn't implemented\n");
275 return;
278 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
279 ok(ret, "got %d\n", ret);
280 ok(val == lcid_en, "got 0x%08x\n", val);
282 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
283 if (ret)
285 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
286 'S','t','a','t','e','s',')',0};
287 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
288 static const WCHAR enW[] = {'e','n','-','U','S',0};
289 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
291 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
293 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
294 ok(ret, "got %d\n", ret);
295 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
296 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
298 skip("Non-English locale\n");
300 else
301 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
303 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
304 ok(ret, "got %d\n", ret);
305 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
306 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
308 skip("Non-English locale\n");
310 else
311 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
313 while (*ptr->name)
315 LANGID langid;
316 LCID lcid;
318 /* make neutral lcid */
319 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
320 lcid = MAKELCID(langid, SORT_DEFAULT);
322 val = 0;
323 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
324 if (ptr->todo & 0x1)
326 todo_wine
327 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
328 wine_dbgstr_w(ptr->name), val, ptr->lcid);
330 else
331 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
332 wine_dbgstr_w(ptr->name), val, ptr->lcid);
334 /* now check LOCALE_SNAME */
335 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
336 if (ptr->todo & 0x2)
337 todo_wine
338 ok(!lstrcmpW(bufferW, ptr->sname) ||
339 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
340 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
341 else
342 ok(!lstrcmpW(bufferW, ptr->sname) ||
343 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
344 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
345 ptr++;
348 else
349 win_skip("English neutral locale not supported\n");
351 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
352 if (!ret) {
353 win_skip("LANG_RUSSIAN locale data unavailable\n");
354 return;
356 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
357 bufferW, COUNTOF(bufferW));
358 if (!ret) {
359 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
360 return;
363 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
364 bufferA[0] = 'a';
365 SetLastError(0xdeadbeef);
366 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
367 bufferA, COUNTOF(bufferA));
368 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
369 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
370 ok(GetLastError() == ERROR_INVALID_FLAGS,
371 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
373 bufferW[0] = 'a';
374 SetLastError(0xdeadbeef);
375 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
376 bufferW, COUNTOF(bufferW));
377 ok(ret == 0,
378 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
379 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
380 ok(GetLastError() == ERROR_INVALID_FLAGS,
381 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
383 /* yes, test empty 13 month entry too */
384 for (i = 0; i < 12; i++) {
385 bufferW[0] = 0;
386 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
387 bufferW, COUNTOF(bufferW));
388 ok(ret, "Expected non zero result\n");
389 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
390 ret, lstrlenW(bufferW));
391 buffer2W[0] = 0;
392 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
393 buffer2W, COUNTOF(buffer2W));
394 ok(ret, "Expected non zero result\n");
395 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
396 ret, lstrlenW(buffer2W));
398 ok(lstrcmpW(bufferW, buffer2W) != 0,
399 "Expected genitive name to differ, got the same for month %d\n", i+1);
401 /* for locale without genitive names nominative returned in both cases */
402 bufferW[0] = 0;
403 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
404 bufferW, COUNTOF(bufferW));
405 ok(ret, "Expected non zero result\n");
406 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
407 ret, lstrlenW(bufferW));
408 buffer2W[0] = 0;
409 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
410 buffer2W, COUNTOF(buffer2W));
411 ok(ret, "Expected non zero result\n");
412 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
413 ret, lstrlenW(buffer2W));
415 ok(lstrcmpW(bufferW, buffer2W) == 0,
416 "Expected same names, got different for month %d\n", i+1);
420 static void test_GetTimeFormatA(void)
422 int ret;
423 SYSTEMTIME curtime;
424 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
425 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
427 memset(&curtime, 2, sizeof(SYSTEMTIME));
428 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
429 SetLastError(0xdeadbeef);
430 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
431 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
432 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
434 curtime.wHour = 8;
435 curtime.wMinute = 56;
436 curtime.wSecond = 13;
437 curtime.wMilliseconds = 22;
438 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
439 SetLastError(0xdeadbeef);
440 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
441 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
442 EXPECT_LENA; EXPECT_EQA;
444 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
445 SetLastError(0xdeadbeef);
446 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
447 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
448 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
450 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
451 SetLastError(0xdeadbeef);
452 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
453 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
454 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
456 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
457 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
458 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
459 EXPECT_LENA;
461 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
462 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
463 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
464 EXPECT_LENA; EXPECT_EQA;
466 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
467 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
468 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
469 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
470 "Expected '', got '%s'\n", buffer );
472 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
473 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
474 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
475 EXPECT_LENA; EXPECT_EQA;
477 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
478 strcpy(Expected, "8:56 AM");
479 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
480 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
481 EXPECT_LENA; EXPECT_EQA;
483 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
484 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
485 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
486 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
487 "Expected '8.@:56AM', got '%s'\n", buffer );
489 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
490 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
491 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
492 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
493 "Expected '', got '%s'\n", buffer );
495 STRINGSA("t/tt", "A/AM"); /* AM time marker */
496 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
498 EXPECT_LENA; EXPECT_EQA;
500 curtime.wHour = 13;
501 STRINGSA("t/tt", "P/PM"); /* PM time marker */
502 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
503 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
504 EXPECT_LENA; EXPECT_EQA;
506 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
507 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
508 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
509 EXPECT_LENA; EXPECT_EQA;
511 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
512 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
513 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
514 EXPECT_LENA; EXPECT_EQA;
516 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
517 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
518 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
519 EXPECT_LENA; EXPECT_EQA;
521 curtime.wHour = 14; /* change this to 14 or 2pm */
522 curtime.wMinute = 5;
523 curtime.wSecond = 3;
524 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 */
525 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
527 EXPECT_LENA; EXPECT_EQA;
529 curtime.wHour = 0;
530 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
531 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
532 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
533 EXPECT_LENA; EXPECT_EQA;
535 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
536 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
537 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
538 EXPECT_LENA; EXPECT_EQA;
540 /* try to convert formatting strings with more than two letters
541 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
542 * NOTE: We expect any letter for which there is an upper case value
543 * we should see a replacement. For letters that DO NOT have
544 * upper case values we should see NO REPLACEMENT.
546 curtime.wHour = 8;
547 curtime.wMinute = 56;
548 curtime.wSecond = 13;
549 curtime.wMilliseconds = 22;
550 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
551 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
552 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
553 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
554 EXPECT_LENA; EXPECT_EQA;
556 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
557 strcpy(buffer, "text");
558 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
559 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
560 EXPECT_EQA;
562 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
563 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
564 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
565 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
566 EXPECT_LENA; EXPECT_EQA;
568 STRINGSA("'''", "'"); /* invalid quoted string */
569 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
570 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
571 EXPECT_LENA; EXPECT_EQA;
573 /* test that msdn suggested single quotation usage works as expected */
574 STRINGSA("''''", "'"); /* single quote mark */
575 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
576 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
577 EXPECT_LENA; EXPECT_EQA;
579 STRINGSA("''HHHHHH", "08"); /* Normal use */
580 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
581 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
582 EXPECT_LENA; EXPECT_EQA;
584 /* and test for normal use of the single quotation mark */
585 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
586 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
587 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
588 EXPECT_LENA; EXPECT_EQA;
590 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
591 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
592 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
593 EXPECT_LENA; EXPECT_EQA;
595 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
596 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
597 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
598 EXPECT_LENA; EXPECT_EQA;
600 curtime.wHour = 25;
601 STRINGSA("'123'tt", ""); /* Invalid time */
602 SetLastError(0xdeadbeef);
603 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
604 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
605 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
607 curtime.wHour = 12;
608 curtime.wMonth = 60; /* Invalid */
609 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
610 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
611 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
612 EXPECT_LENA; EXPECT_EQA;
615 static void test_GetDateFormatA(void)
617 int ret;
618 SYSTEMTIME curtime;
619 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
620 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
621 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
622 char Broken[BUFFER_SIZE];
623 char short_day[10], month[10], genitive_month[10];
625 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
626 STRINGSA("ddd',' MMM dd yy","");
627 SetLastError(0xdeadbeef);
628 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
629 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
630 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
632 curtime.wYear = 2002;
633 curtime.wMonth = 5;
634 curtime.wDay = 4;
635 curtime.wDayOfWeek = 3;
636 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
637 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
638 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
639 EXPECT_LENA; EXPECT_EQA;
641 /* Same as above but with LOCALE_NOUSEROVERRIDE */
642 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
643 SetLastError(0xdeadbeef);
644 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
645 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
646 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
647 EXPECT_EQA;
649 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
650 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
651 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
652 EXPECT_LENA; EXPECT_EQA;
654 curtime.wHour = 36; /* Invalid */
655 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
656 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
657 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
658 EXPECT_LENA; EXPECT_EQA;
660 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
661 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
662 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
663 EXPECT_EQA;
665 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
666 SetLastError(0xdeadbeef);
667 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
668 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
669 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
671 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
672 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
673 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
674 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
675 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
677 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
678 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
679 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
680 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
681 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
682 "got an unexpected date string '%s'\n", buffer);
684 /* test for expected DATE_YEARMONTH behavior with null format */
685 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
686 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
687 SetLastError(0xdeadbeef);
688 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
689 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
690 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
691 EXPECT_EQA;
693 /* Test that using invalid DATE_* flags results in the correct error */
694 /* and return values */
695 STRINGSA("m/d/y", ""); /* Invalid flags */
696 SetLastError(0xdeadbeef);
697 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
698 &curtime, input, buffer, COUNTOF(buffer));
699 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
700 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
702 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
703 if (!ret)
705 win_skip("LANG_RUSSIAN locale data unavailable\n");
706 return;
709 /* month part should be in genitive form */
710 strcpy(genitive_month, buffer + 2);
711 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 strcpy(month, buffer);
714 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
716 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
718 strcpy(short_day, buffer);
720 STRINGSA("dd MMMMddd dd", "");
721 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
722 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
723 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
724 EXPECT_EQA;
726 STRINGSA("MMMMddd dd", "");
727 sprintf(Expected, "%s%s 04", month, short_day);
728 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
729 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
730 EXPECT_EQA;
732 STRINGSA("MMMMddd", "");
733 sprintf(Expected, "%s%s", month, short_day);
734 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
735 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
736 EXPECT_EQA;
738 STRINGSA("MMMMdd", "");
739 sprintf(Expected, "%s04", genitive_month);
740 sprintf(Broken, "%s04", month);
741 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
742 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
743 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
744 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
745 "Expected '%s', got '%s'\n", Expected, buffer);
747 STRINGSA("MMMMdd ddd", "");
748 sprintf(Expected, "%s04 %s", genitive_month, short_day);
749 sprintf(Broken, "%s04 %s", month, short_day);
750 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
751 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
752 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
753 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
754 "Expected '%s', got '%s'\n", Expected, buffer);
756 STRINGSA("dd dddMMMM", "");
757 sprintf(Expected, "04 %s%s", short_day, month);
758 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
759 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
760 EXPECT_EQA;
762 STRINGSA("dd dddMMMM ddd MMMMdd", "");
763 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
764 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
765 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
766 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
767 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
768 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
769 "Expected '%s', got '%s'\n", Expected, buffer);
771 /* with literal part */
772 STRINGSA("ddd',' MMMM dd", "");
773 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
774 sprintf(Broken, "%s, %s 04", short_day, month);
775 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
776 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
777 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
778 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
779 "Expected '%s', got '%s'\n", Expected, buffer);
782 static void test_GetDateFormatW(void)
784 int ret;
785 SYSTEMTIME curtime;
786 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
787 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
789 STRINGSW("",""); /* If flags is not zero then format must be NULL */
790 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
791 input, buffer, COUNTOF(buffer));
792 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
794 win_skip("GetDateFormatW is not implemented\n");
795 return;
797 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
798 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
799 EXPECT_EQW;
801 STRINGSW("",""); /* NULL buffer, len > 0 */
802 SetLastError(0xdeadbeef);
803 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
804 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
805 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
807 STRINGSW("",""); /* NULL buffer, len == 0 */
808 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
809 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
810 EXPECT_LENW; EXPECT_EQW;
812 curtime.wYear = 2002;
813 curtime.wMonth = 10;
814 curtime.wDay = 23;
815 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
816 curtime.wHour = 65432; /* Invalid */
817 curtime.wMinute = 34512; /* Invalid */
818 curtime.wSecond = 65535; /* Invalid */
819 curtime.wMilliseconds = 12345;
820 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
821 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
822 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
823 EXPECT_LENW; EXPECT_EQW;
825 /* Limit tests */
827 curtime.wYear = 1601;
828 curtime.wMonth = 1;
829 curtime.wDay = 1;
830 curtime.wDayOfWeek = 0; /* Irrelevant */
831 curtime.wHour = 0;
832 curtime.wMinute = 0;
833 curtime.wSecond = 0;
834 curtime.wMilliseconds = 0;
835 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
836 SetLastError(0xdeadbeef);
837 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
838 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
839 EXPECT_LENW; EXPECT_EQW;
841 curtime.wYear = 1600;
842 curtime.wMonth = 12;
843 curtime.wDay = 31;
844 curtime.wDayOfWeek = 0; /* Irrelevant */
845 curtime.wHour = 23;
846 curtime.wMinute = 59;
847 curtime.wSecond = 59;
848 curtime.wMilliseconds = 999;
849 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
850 SetLastError(0xdeadbeef);
851 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
852 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
853 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
857 #define CY_POS_LEFT 0
858 #define CY_POS_RIGHT 1
859 #define CY_POS_LEFT_SPACE 2
860 #define CY_POS_RIGHT_SPACE 3
862 static void test_GetCurrencyFormatA(void)
864 static char szDot[] = { '.', '\0' };
865 static char szComma[] = { ',', '\0' };
866 static char szDollar[] = { '$', '\0' };
867 int ret;
868 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
869 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
870 CURRENCYFMTA format;
872 memset(&format, 0, sizeof(format));
874 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
875 SetLastError(0xdeadbeef);
876 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
877 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
878 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
880 STRINGSA("23,53",""); /* Invalid character --> Error */
881 SetLastError(0xdeadbeef);
882 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
883 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
884 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
886 STRINGSA("--",""); /* Double '-' --> Error */
887 SetLastError(0xdeadbeef);
888 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
889 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
890 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
892 STRINGSA("0-",""); /* Trailing '-' --> Error */
893 SetLastError(0xdeadbeef);
894 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
895 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
896 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
898 STRINGSA("0..",""); /* Double '.' --> Error */
899 SetLastError(0xdeadbeef);
900 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
901 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
902 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
904 STRINGSA(" 0.1",""); /* Leading space --> Error */
905 SetLastError(0xdeadbeef);
906 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
907 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
908 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
910 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
911 SetLastError(0xdeadbeef);
912 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
913 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
914 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
916 STRINGSA("2353",""); /* Format and flags given --> Error */
917 SetLastError(0xdeadbeef);
918 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
919 ok( !ret, "Expected ret == 0, got %d\n", ret);
920 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
921 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
923 STRINGSA("2353",""); /* Invalid format --> Error */
924 SetLastError(0xdeadbeef);
925 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
926 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
927 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
929 STRINGSA("2353","$2,353.00"); /* Valid number */
930 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
931 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
932 EXPECT_LENA; EXPECT_EQA;
934 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
935 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
936 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
937 EXPECT_LENA; EXPECT_EQA;
939 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
940 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
941 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942 EXPECT_LENA; EXPECT_EQA;
944 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
945 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 EXPECT_LENA; EXPECT_EQA;
949 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
950 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
951 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
952 EXPECT_LENA; EXPECT_EQA;
954 format.NumDigits = 0; /* No decimal separator */
955 format.LeadingZero = 0;
956 format.Grouping = 0; /* No grouping char */
957 format.NegativeOrder = 0;
958 format.PositiveOrder = CY_POS_LEFT;
959 format.lpDecimalSep = szDot;
960 format.lpThousandSep = szComma;
961 format.lpCurrencySymbol = szDollar;
963 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
964 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
965 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
966 EXPECT_LENA; EXPECT_EQA;
968 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
969 STRINGSA("2353","$2353.0");
970 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
971 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
972 EXPECT_LENA; EXPECT_EQA;
974 format.Grouping = 2; /* Group by 100's */
975 STRINGSA("2353","$23,53.0");
976 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
977 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
978 EXPECT_LENA; EXPECT_EQA;
980 STRINGSA("235","$235.0"); /* Grouping of a positive number */
981 format.Grouping = 3;
982 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
983 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
984 EXPECT_LENA; EXPECT_EQA;
986 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
987 format.NegativeOrder = 2;
988 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
989 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
990 EXPECT_LENA; EXPECT_EQA;
992 format.LeadingZero = 1; /* Always provide leading zero */
993 STRINGSA(".5","$0.5");
994 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
995 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
996 EXPECT_LENA; EXPECT_EQA;
998 format.PositiveOrder = CY_POS_RIGHT;
999 STRINGSA("1","1.0$");
1000 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1001 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1002 EXPECT_LENA; EXPECT_EQA;
1004 format.PositiveOrder = CY_POS_LEFT_SPACE;
1005 STRINGSA("1","$ 1.0");
1006 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1007 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1008 EXPECT_LENA; EXPECT_EQA;
1010 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1011 STRINGSA("1","1.0 $");
1012 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1013 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1014 EXPECT_LENA; EXPECT_EQA;
1016 format.NegativeOrder = 0;
1017 STRINGSA("-1","($1.0)");
1018 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1019 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1020 EXPECT_LENA; EXPECT_EQA;
1022 format.NegativeOrder = 1;
1023 STRINGSA("-1","-$1.0");
1024 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1025 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1026 EXPECT_LENA; EXPECT_EQA;
1028 format.NegativeOrder = 2;
1029 STRINGSA("-1","$-1.0");
1030 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1031 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1032 EXPECT_LENA; EXPECT_EQA;
1034 format.NegativeOrder = 3;
1035 STRINGSA("-1","$1.0-");
1036 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1037 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1038 EXPECT_LENA; EXPECT_EQA;
1040 format.NegativeOrder = 4;
1041 STRINGSA("-1","(1.0$)");
1042 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1043 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1044 EXPECT_LENA; EXPECT_EQA;
1046 format.NegativeOrder = 5;
1047 STRINGSA("-1","-1.0$");
1048 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1049 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1050 EXPECT_LENA; EXPECT_EQA;
1052 format.NegativeOrder = 6;
1053 STRINGSA("-1","1.0-$");
1054 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1055 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1056 EXPECT_LENA; EXPECT_EQA;
1058 format.NegativeOrder = 7;
1059 STRINGSA("-1","1.0$-");
1060 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1061 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1062 EXPECT_LENA; EXPECT_EQA;
1064 format.NegativeOrder = 8;
1065 STRINGSA("-1","-1.0 $");
1066 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1067 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1068 EXPECT_LENA; EXPECT_EQA;
1070 format.NegativeOrder = 9;
1071 STRINGSA("-1","-$ 1.0");
1072 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1073 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1074 EXPECT_LENA; EXPECT_EQA;
1076 format.NegativeOrder = 10;
1077 STRINGSA("-1","1.0 $-");
1078 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1079 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1080 EXPECT_LENA; EXPECT_EQA;
1082 format.NegativeOrder = 11;
1083 STRINGSA("-1","$ 1.0-");
1084 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1085 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1086 EXPECT_LENA; EXPECT_EQA;
1088 format.NegativeOrder = 12;
1089 STRINGSA("-1","$ -1.0");
1090 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1091 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1092 EXPECT_LENA; EXPECT_EQA;
1094 format.NegativeOrder = 13;
1095 STRINGSA("-1","1.0- $");
1096 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1097 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1098 EXPECT_LENA; EXPECT_EQA;
1100 format.NegativeOrder = 14;
1101 STRINGSA("-1","($ 1.0)");
1102 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1103 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1104 EXPECT_LENA; EXPECT_EQA;
1106 format.NegativeOrder = 15;
1107 STRINGSA("-1","(1.0 $)");
1108 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENA; EXPECT_EQA;
1113 #define NEG_PARENS 0 /* "(1.1)" */
1114 #define NEG_LEFT 1 /* "-1.1" */
1115 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1116 #define NEG_RIGHT 3 /* "1.1-" */
1117 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1119 static void test_GetNumberFormatA(void)
1121 static char szDot[] = { '.', '\0' };
1122 static char szComma[] = { ',', '\0' };
1123 int ret;
1124 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1125 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1126 NUMBERFMTA format;
1128 memset(&format, 0, sizeof(format));
1130 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1131 SetLastError(0xdeadbeef);
1132 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1133 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1134 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1136 STRINGSA("23,53",""); /* Invalid character --> Error */
1137 SetLastError(0xdeadbeef);
1138 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1139 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1140 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1142 STRINGSA("--",""); /* Double '-' --> Error */
1143 SetLastError(0xdeadbeef);
1144 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1145 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1146 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1148 STRINGSA("0-",""); /* Trailing '-' --> Error */
1149 SetLastError(0xdeadbeef);
1150 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1151 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1152 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1154 STRINGSA("0..",""); /* Double '.' --> Error */
1155 SetLastError(0xdeadbeef);
1156 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1157 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1158 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1160 STRINGSA(" 0.1",""); /* Leading space --> Error */
1161 SetLastError(0xdeadbeef);
1162 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1163 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1164 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1166 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1167 SetLastError(0xdeadbeef);
1168 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1169 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1170 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1172 STRINGSA("2353",""); /* Format and flags given --> Error */
1173 SetLastError(0xdeadbeef);
1174 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1175 ok( !ret, "Expected ret == 0, got %d\n", ret);
1176 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1177 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1179 STRINGSA("2353",""); /* Invalid format --> Error */
1180 SetLastError(0xdeadbeef);
1181 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1182 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1183 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1185 STRINGSA("2353","2,353.00"); /* Valid number */
1186 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1187 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1188 EXPECT_LENA; EXPECT_EQA;
1190 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1191 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1192 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1193 EXPECT_LENA; EXPECT_EQA;
1195 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1196 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1197 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1198 EXPECT_LENA; EXPECT_EQA;
1200 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1201 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1202 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1203 EXPECT_LENA; EXPECT_EQA;
1205 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1206 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1207 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1208 EXPECT_LENA; EXPECT_EQA;
1210 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1211 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1212 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1213 EXPECT_LENA; EXPECT_EQA;
1215 format.NumDigits = 0; /* No decimal separator */
1216 format.LeadingZero = 0;
1217 format.Grouping = 0; /* No grouping char */
1218 format.NegativeOrder = 0;
1219 format.lpDecimalSep = szDot;
1220 format.lpThousandSep = szComma;
1222 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1223 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1224 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1225 EXPECT_LENA; EXPECT_EQA;
1227 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1228 STRINGSA("2353","2353.0");
1229 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1230 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1231 EXPECT_LENA; EXPECT_EQA;
1233 format.Grouping = 2; /* Group by 100's */
1234 STRINGSA("2353","23,53.0");
1235 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1237 EXPECT_LENA; EXPECT_EQA;
1239 STRINGSA("235","235.0"); /* Grouping of a positive number */
1240 format.Grouping = 3;
1241 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1242 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1243 EXPECT_LENA; EXPECT_EQA;
1245 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1246 format.NegativeOrder = NEG_LEFT;
1247 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1248 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1249 EXPECT_LENA; EXPECT_EQA;
1251 format.LeadingZero = 1; /* Always provide leading zero */
1252 STRINGSA(".5","0.5");
1253 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1254 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1255 EXPECT_LENA; EXPECT_EQA;
1257 format.NegativeOrder = NEG_PARENS;
1258 STRINGSA("-1","(1.0)");
1259 ret = GetNumberFormatA(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.NegativeOrder = NEG_LEFT;
1264 STRINGSA("-1","-1.0");
1265 ret = GetNumberFormatA(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 format.NegativeOrder = NEG_LEFT_SPACE;
1270 STRINGSA("-1","- 1.0");
1271 ret = GetNumberFormatA(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 format.NegativeOrder = NEG_RIGHT;
1276 STRINGSA("-1","1.0-");
1277 ret = GetNumberFormatA(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.NegativeOrder = NEG_RIGHT_SPACE;
1282 STRINGSA("-1","1.0 -");
1283 ret = GetNumberFormatA(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 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1289 if (IsValidLocale(lcid, 0))
1291 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1292 Expected[3] = 160; /* Non breaking space */
1293 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1294 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1295 EXPECT_LENA; EXPECT_EQA;
1299 struct comparestringa_entry {
1300 LCID lcid;
1301 DWORD flags;
1302 const char *first;
1303 int first_len;
1304 const char *second;
1305 int second_len;
1306 int ret;
1309 static const struct comparestringa_entry comparestringa_data[] = {
1310 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1311 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1312 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1313 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1314 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1315 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1316 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1317 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1318 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1319 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1320 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1321 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1322 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1323 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1324 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1325 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1326 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1327 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1328 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1329 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1330 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1331 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1332 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1333 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1334 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1335 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1336 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1337 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1338 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1339 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1342 static void test_CompareStringA(void)
1344 int ret, i;
1345 char a[256];
1346 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1348 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1350 const struct comparestringa_entry *entry = &comparestringa_data[i];
1352 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1353 entry->second, entry->second_len);
1354 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1357 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1358 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1360 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1361 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1363 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1364 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1366 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1367 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1369 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1371 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1372 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1374 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1375 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1377 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1378 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1380 /* test for CompareStringA flags */
1381 SetLastError(0xdeadbeef);
1382 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1383 ok(GetLastError() == ERROR_INVALID_FLAGS,
1384 "unexpected error code %d\n", GetLastError());
1385 ok(!ret, "CompareStringA must fail with invalid flag\n");
1387 SetLastError(0xdeadbeef);
1388 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1389 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1390 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1391 /* end of test for CompareStringA flags */
1393 ret = lstrcmpA("", "");
1394 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1396 ret = lstrcmpA(NULL, NULL);
1397 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1399 ret = lstrcmpA("", NULL);
1400 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1402 ret = lstrcmpA(NULL, "");
1403 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1406 if (0) { /* this requires collation table patch to make it MS compatible */
1407 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1408 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1410 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1411 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1413 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1414 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1416 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1417 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1419 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1420 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1422 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1423 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1425 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1426 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1428 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1429 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1431 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1432 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1434 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1435 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1437 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1438 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1440 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1441 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1445 /* WinXP handles embedded NULLs differently than earlier versions */
1446 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1447 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1449 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1450 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);
1452 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1453 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1455 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1456 ok(ret == CSTR_EQUAL || /* win2k */
1457 ret == CSTR_GREATER_THAN,
1458 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1460 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1461 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1463 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1464 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1466 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1467 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1469 ret = lstrcmpiA("#", ".");
1470 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1472 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1474 /* \xB9 character lies between a and b */
1475 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1476 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1477 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1478 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1480 memset(a, 'a', sizeof(a));
1481 SetLastError(0xdeadbeef);
1482 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1483 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1484 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1487 struct comparestringex_test {
1488 const char *locale;
1489 DWORD flags;
1490 const WCHAR first[2];
1491 const WCHAR second[2];
1492 INT ret;
1493 INT broken;
1494 BOOL todo;
1497 static const struct comparestringex_test comparestringex_tests[] = {
1498 /* default behavior */
1499 { /* 0 */
1500 "tr-TR", 0,
1501 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
1503 { /* 1 */
1504 "tr-TR", 0,
1505 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1507 { /* 2 */
1508 "tr-TR", 0,
1509 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1511 { /* 3 */
1512 "tr-TR", 0,
1513 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1515 { /* 4 */
1516 "tr-TR", 0,
1517 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1519 { /* 5 */
1520 "tr-TR", 0,
1521 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1523 /* with NORM_IGNORECASE */
1524 { /* 6 */
1525 "tr-TR", NORM_IGNORECASE,
1526 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
1528 { /* 7 */
1529 "tr-TR", NORM_IGNORECASE,
1530 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1532 { /* 8 */
1533 "tr-TR", NORM_IGNORECASE,
1534 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1536 { /* 9 */
1537 "tr-TR", NORM_IGNORECASE,
1538 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1540 { /* 10 */
1541 "tr-TR", NORM_IGNORECASE,
1542 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1544 { /* 11 */
1545 "tr-TR", NORM_IGNORECASE,
1546 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1548 /* with NORM_LINGUISTIC_CASING */
1549 { /* 12 */
1550 "tr-TR", NORM_LINGUISTIC_CASING,
1551 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1553 { /* 13 */
1554 "tr-TR", NORM_LINGUISTIC_CASING,
1555 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1557 { /* 14 */
1558 "tr-TR", NORM_LINGUISTIC_CASING,
1559 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1561 { /* 15 */
1562 "tr-TR", NORM_LINGUISTIC_CASING,
1563 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1565 { /* 16 */
1566 "tr-TR", NORM_LINGUISTIC_CASING,
1567 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1569 { /* 17 */
1570 "tr-TR", NORM_LINGUISTIC_CASING,
1571 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1573 /* with LINGUISTIC_IGNORECASE */
1574 { /* 18 */
1575 "tr-TR", LINGUISTIC_IGNORECASE,
1576 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
1578 { /* 19 */
1579 "tr-TR", LINGUISTIC_IGNORECASE,
1580 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
1582 { /* 20 */
1583 "tr-TR", LINGUISTIC_IGNORECASE,
1584 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1586 { /* 21 */
1587 "tr-TR", LINGUISTIC_IGNORECASE,
1588 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1590 { /* 22 */
1591 "tr-TR", LINGUISTIC_IGNORECASE,
1592 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
1594 { /* 23 */
1595 "tr-TR", LINGUISTIC_IGNORECASE,
1596 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1598 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
1599 { /* 24 */
1600 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1601 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1603 { /* 25 */
1604 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1605 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
1607 { /* 26 */
1608 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1609 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1611 { /* 27 */
1612 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1613 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1615 { /* 28 */
1616 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1617 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1619 { /* 29 */
1620 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
1621 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
1623 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
1624 { /* 30 */
1625 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1626 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
1628 { /* 31 */
1629 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1630 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1632 { /* 32 */
1633 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1634 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1636 { /* 33 */
1637 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1638 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
1640 { /* 34 */
1641 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1642 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
1644 { /* 35 */
1645 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
1646 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
1650 static void test_CompareStringEx(void)
1652 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
1653 WCHAR locale[6];
1654 INT ret, i;
1656 /* CompareStringEx is only available on Vista+ */
1657 if (!pCompareStringEx)
1659 win_skip("CompareStringEx not supported\n");
1660 return;
1663 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
1665 const struct comparestringex_test *e = &comparestringex_tests[i];
1667 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
1668 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
1669 if (e->todo)
1671 todo_wine ok(ret == e->ret || broken(ret == e->broken),
1672 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1674 else
1676 ok(ret == e->ret || broken(ret == e->broken),
1677 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
1683 static void test_LCMapStringA(void)
1685 int ret, ret2;
1686 char buf[256], buf2[256];
1687 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1688 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1689 static const char symbols_stripped[] = "justateststring1";
1691 SetLastError(0xdeadbeef);
1692 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1693 lower_case, -1, buf, sizeof(buf));
1694 ok(ret == lstrlenA(lower_case) + 1,
1695 "ret %d, error %d, expected value %d\n",
1696 ret, GetLastError(), lstrlenA(lower_case) + 1);
1697 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1699 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1700 upper_case, -1, buf, sizeof(buf));
1701 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1702 ok(GetLastError() == ERROR_INVALID_FLAGS,
1703 "unexpected error code %d\n", GetLastError());
1705 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1706 upper_case, -1, buf, sizeof(buf));
1707 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1708 ok(GetLastError() == ERROR_INVALID_FLAGS,
1709 "unexpected error code %d\n", GetLastError());
1711 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1712 upper_case, -1, buf, sizeof(buf));
1713 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1714 ok(GetLastError() == ERROR_INVALID_FLAGS,
1715 "unexpected error code %d\n", GetLastError());
1717 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1718 upper_case, -1, buf, sizeof(buf));
1719 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1720 ok(GetLastError() == ERROR_INVALID_FLAGS,
1721 "unexpected error code %d\n", GetLastError());
1723 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1724 SetLastError(0xdeadbeef);
1725 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1726 upper_case, -1, buf, sizeof(buf));
1727 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1728 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1730 /* test LCMAP_LOWERCASE */
1731 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1732 upper_case, -1, buf, sizeof(buf));
1733 ok(ret == lstrlenA(upper_case) + 1,
1734 "ret %d, error %d, expected value %d\n",
1735 ret, GetLastError(), lstrlenA(upper_case) + 1);
1736 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1738 /* test LCMAP_UPPERCASE */
1739 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1740 lower_case, -1, buf, sizeof(buf));
1741 ok(ret == lstrlenA(lower_case) + 1,
1742 "ret %d, error %d, expected value %d\n",
1743 ret, GetLastError(), lstrlenA(lower_case) + 1);
1744 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1746 /* test buffer overflow */
1747 SetLastError(0xdeadbeef);
1748 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1749 lower_case, -1, buf, 4);
1750 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1751 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1753 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1754 lstrcpyA(buf, lower_case);
1755 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1756 buf, -1, buf, sizeof(buf));
1757 if (!ret) /* Win9x */
1758 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1759 else
1761 ok(ret == lstrlenA(lower_case) + 1,
1762 "ret %d, error %d, expected value %d\n",
1763 ret, GetLastError(), lstrlenA(lower_case) + 1);
1764 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1766 lstrcpyA(buf, upper_case);
1767 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1768 buf, -1, buf, sizeof(buf));
1769 if (!ret) /* Win9x */
1770 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1771 else
1773 ok(ret == lstrlenA(upper_case) + 1,
1774 "ret %d, error %d, expected value %d\n",
1775 ret, GetLastError(), lstrlenA(lower_case) + 1);
1776 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1779 /* otherwise src == dst should fail */
1780 SetLastError(0xdeadbeef);
1781 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1782 buf, 10, buf, sizeof(buf));
1783 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1784 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1785 "unexpected error code %d\n", GetLastError());
1786 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1788 /* test whether '\0' is always appended */
1789 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1790 upper_case, -1, buf, sizeof(buf));
1791 ok(ret, "LCMapStringA must succeed\n");
1792 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1793 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1794 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1795 ok(ret2, "LCMapStringA must succeed\n");
1796 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1797 ok(ret == ret2, "lengths of sort keys must be equal\n");
1798 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1800 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1801 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1802 upper_case, -1, buf, sizeof(buf));
1803 ok(ret, "LCMapStringA must succeed\n");
1804 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1805 lower_case, -1, buf2, sizeof(buf2));
1806 ok(ret2, "LCMapStringA must succeed\n");
1807 ok(ret == ret2, "lengths of sort keys must be equal\n");
1808 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1810 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1811 results from plain LCMAP_SORTKEY on Vista */
1813 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1814 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1815 lower_case, -1, buf, sizeof(buf));
1816 ok(ret, "LCMapStringA must succeed\n");
1817 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1818 symbols_stripped, -1, buf2, sizeof(buf2));
1819 ok(ret2, "LCMapStringA must succeed\n");
1820 ok(ret == ret2, "lengths of sort keys must be equal\n");
1821 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1823 /* test NORM_IGNORENONSPACE */
1824 lstrcpyA(buf, "foo");
1825 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1826 lower_case, -1, buf, sizeof(buf));
1827 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1828 lstrlenA(lower_case) + 1, ret);
1829 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1831 /* test NORM_IGNORESYMBOLS */
1832 lstrcpyA(buf, "foo");
1833 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1834 lower_case, -1, buf, sizeof(buf));
1835 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1836 lstrlenA(symbols_stripped) + 1, ret);
1837 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1839 /* test srclen = 0 */
1840 SetLastError(0xdeadbeef);
1841 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1842 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1843 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1844 "unexpected error code %d\n", GetLastError());
1847 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1849 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1851 int ret, ret2;
1852 WCHAR buf[256], buf2[256];
1853 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1855 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1856 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1857 if (broken(ret))
1858 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1859 else
1861 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1862 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1863 func_name, GetLastError());
1866 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1867 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1868 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1869 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1870 func_name, GetLastError());
1872 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1873 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1874 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1875 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1876 func_name, GetLastError());
1878 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1879 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1880 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1881 func_name);
1882 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1883 func_name, GetLastError());
1885 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1886 SetLastError(0xdeadbeef);
1887 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1888 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1889 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1890 func_name, GetLastError());
1891 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1893 /* test LCMAP_LOWERCASE */
1894 ret = func_ptr(LCMAP_LOWERCASE,
1895 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1896 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1897 ret, GetLastError(), lstrlenW(upper_case) + 1);
1898 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1900 /* test LCMAP_UPPERCASE */
1901 ret = func_ptr(LCMAP_UPPERCASE,
1902 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1903 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1904 ret, GetLastError(), lstrlenW(lower_case) + 1);
1905 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1907 /* test buffer overflow */
1908 SetLastError(0xdeadbeef);
1909 ret = func_ptr(LCMAP_UPPERCASE,
1910 lower_case, -1, buf, 4);
1911 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1912 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1914 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1915 lstrcpyW(buf, lower_case);
1916 ret = func_ptr(LCMAP_UPPERCASE,
1917 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1918 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1919 ret, GetLastError(), lstrlenW(lower_case) + 1);
1920 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1922 lstrcpyW(buf, upper_case);
1923 ret = func_ptr(LCMAP_LOWERCASE,
1924 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1925 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1926 ret, GetLastError(), lstrlenW(lower_case) + 1);
1927 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1929 /* otherwise src == dst should fail */
1930 SetLastError(0xdeadbeef);
1931 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1932 buf, 10, buf, sizeof(buf));
1933 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1934 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1935 "%s unexpected error code %d\n", func_name, GetLastError());
1936 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1938 /* test whether '\0' is always appended */
1939 ret = func_ptr(LCMAP_SORTKEY,
1940 upper_case, -1, buf, sizeof(buf));
1941 ok(ret, "%s func_ptr must succeed\n", func_name);
1942 ret2 = func_ptr(LCMAP_SORTKEY,
1943 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1944 ok(ret, "%s func_ptr must succeed\n", func_name);
1945 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1946 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1948 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1949 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1950 upper_case, -1, buf, sizeof(buf));
1951 ok(ret, "%s func_ptr must succeed\n", func_name);
1952 ret2 = func_ptr(LCMAP_SORTKEY,
1953 lower_case, -1, buf2, sizeof(buf2));
1954 ok(ret2, "%s func_ptr must succeed\n", func_name);
1955 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1956 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1958 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1959 results from plain LCMAP_SORTKEY on Vista */
1961 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1962 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1963 lower_case, -1, buf, sizeof(buf));
1964 ok(ret, "%s func_ptr must succeed\n", func_name);
1965 ret2 = func_ptr(LCMAP_SORTKEY,
1966 symbols_stripped, -1, buf2, sizeof(buf2));
1967 ok(ret2, "%s func_ptr must succeed\n", func_name);
1968 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1969 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1971 /* test NORM_IGNORENONSPACE */
1972 lstrcpyW(buf, fooW);
1973 ret = func_ptr(NORM_IGNORENONSPACE,
1974 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1975 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1976 lstrlenW(lower_case) + 1, ret);
1977 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1979 /* test NORM_IGNORESYMBOLS */
1980 lstrcpyW(buf, fooW);
1981 ret = func_ptr(NORM_IGNORESYMBOLS,
1982 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1983 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1984 lstrlenW(symbols_stripped) + 1, ret);
1985 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1987 /* test srclen = 0 */
1988 SetLastError(0xdeadbeef);
1989 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1990 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1991 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1992 "%s unexpected error code %d\n", func_name, GetLastError());
1995 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1997 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2000 static void test_LCMapStringW(void)
2002 int ret;
2003 WCHAR buf[256];
2005 trace("testing LCMapStringW\n");
2007 SetLastError(0xdeadbeef);
2008 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2009 todo_wine {
2010 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2011 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2014 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2017 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2019 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2022 static void test_LCMapStringEx(void)
2024 int ret;
2025 WCHAR buf[256];
2027 if (!pLCMapStringEx)
2029 win_skip( "LCMapStringEx not available\n" );
2030 return;
2033 trace("testing LCMapStringEx\n");
2035 SetLastError(0xdeadbeef);
2036 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2037 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2038 todo_wine {
2039 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2040 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2043 /* test reserved parameters */
2044 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2045 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2046 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2047 ret, GetLastError(), lstrlenW(upper_case) + 1);
2048 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2050 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2051 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2052 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2053 ret, GetLastError(), lstrlenW(upper_case) + 1);
2054 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2056 /* crashes on native */
2057 if(0)
2058 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2059 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2061 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2064 struct neutralsublang_name_t {
2065 WCHAR name[3];
2066 LCID lcid;
2067 int todo;
2070 static const struct neutralsublang_name_t neutralsublang_names[] = {
2071 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2072 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2073 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2074 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2075 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2076 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2077 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2078 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2079 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2080 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2081 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2082 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2083 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2084 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2085 { {0} }
2088 static void test_LocaleNameToLCID(void)
2090 LCID lcid;
2091 INT ret;
2092 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2093 static const WCHAR enW[] = {'e','n',0};
2095 if (!pLocaleNameToLCID)
2097 win_skip( "LocaleNameToLCID not available\n" );
2098 return;
2101 /* special cases */
2102 buffer[0] = 0;
2103 SetLastError(0xdeadbeef);
2104 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2105 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2106 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2107 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2108 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2109 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2111 buffer[0] = 0;
2112 SetLastError(0xdeadbeef);
2113 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2114 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2115 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2116 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2117 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2118 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2120 buffer[0] = 0;
2121 SetLastError(0xdeadbeef);
2122 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2123 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2124 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2125 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2126 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2128 /* bad name */
2129 SetLastError(0xdeadbeef);
2130 lcid = pLocaleNameToLCID(fooW, 0);
2131 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2132 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
2134 /* english neutral name */
2135 lcid = pLocaleNameToLCID(enW, 0);
2136 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2137 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2138 if (lcid)
2140 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2142 while (*ptr->name)
2144 lcid = pLocaleNameToLCID(ptr->name, 0);
2145 if (ptr->todo)
2146 todo_wine
2147 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2148 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2149 else
2150 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2151 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2153 *buffer = 0;
2154 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2155 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2156 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2157 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2159 ptr++;
2164 /* this requires collation table patch to make it MS compatible */
2165 static const char * const strings_sorted[] =
2167 "'",
2168 "-",
2169 "!",
2170 "\"",
2171 ".",
2172 ":",
2173 "\\",
2174 "_",
2175 "`",
2176 "{",
2177 "}",
2178 "+",
2179 "0",
2180 "1",
2181 "2",
2182 "3",
2183 "4",
2184 "5",
2185 "6",
2186 "7",
2187 "8",
2188 "9",
2189 "a",
2190 "A",
2191 "b",
2192 "B",
2193 "c",
2197 static const char * const strings[] =
2199 "C",
2200 "\"",
2201 "9",
2202 "'",
2203 "}",
2204 "-",
2205 "7",
2206 "+",
2207 "`",
2208 "1",
2209 "a",
2210 "5",
2211 "\\",
2212 "8",
2213 "B",
2214 "3",
2215 "_",
2216 "6",
2217 "{",
2218 "2",
2219 "c",
2220 "4",
2221 "!",
2222 "0",
2223 "A",
2224 ":",
2225 "b",
2229 static int compare_string1(const void *e1, const void *e2)
2231 const char *s1 = *(const char *const *)e1;
2232 const char *s2 = *(const char *const *)e2;
2234 return lstrcmpA(s1, s2);
2237 static int compare_string2(const void *e1, const void *e2)
2239 const char *s1 = *(const char *const *)e1;
2240 const char *s2 = *(const char *const *)e2;
2242 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2245 static int compare_string3(const void *e1, const void *e2)
2247 const char *s1 = *(const char *const *)e1;
2248 const char *s2 = *(const char *const *)e2;
2249 char key1[256], key2[256];
2251 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2252 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2253 return strcmp(key1, key2);
2256 static void test_sorting(void)
2258 char buf[256];
2259 char **str_buf = (char **)buf;
2260 int i;
2262 assert(sizeof(buf) >= sizeof(strings));
2264 /* 1. sort using lstrcmpA */
2265 memcpy(buf, strings, sizeof(strings));
2266 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2267 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2269 ok(!strcmp(strings_sorted[i], str_buf[i]),
2270 "qsort using lstrcmpA failed for element %d\n", i);
2272 /* 2. sort using CompareStringA */
2273 memcpy(buf, strings, sizeof(strings));
2274 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2275 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2277 ok(!strcmp(strings_sorted[i], str_buf[i]),
2278 "qsort using CompareStringA failed for element %d\n", i);
2280 /* 3. sort using sort keys */
2281 memcpy(buf, strings, sizeof(strings));
2282 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2283 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2285 ok(!strcmp(strings_sorted[i], str_buf[i]),
2286 "qsort using sort keys failed for element %d\n", i);
2290 static void test_FoldStringA(void)
2292 int ret, i, j;
2293 BOOL is_special;
2294 char src[256], dst[256];
2295 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2296 static const char digits_dst[] = { '1','2','3','\0' };
2297 static const char composite_src[] =
2299 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2300 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2301 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2302 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2303 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2304 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2305 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2306 0xfb,0xfc,0xfd,0xff,'\0'
2308 static const char composite_dst[] =
2310 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2311 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2312 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2313 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2314 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2315 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2316 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2317 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2318 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2319 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2320 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2321 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2322 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2323 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2324 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2326 static const char composite_dst_alt[] =
2328 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2329 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2330 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2331 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2332 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2333 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2334 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2335 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2336 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2337 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2338 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2339 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2340 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2341 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2342 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2344 static const char ligatures_src[] =
2346 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2348 static const char ligatures_dst[] =
2350 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2352 static const struct special
2354 char src;
2355 char dst[4];
2356 } foldczone_special[] =
2358 /* src dst */
2359 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2360 { 0x98, { 0x20, 0x7e, 0x00 } },
2361 { 0x99, { 0x54, 0x4d, 0x00 } },
2362 { 0xa0, { 0x20, 0x00 } },
2363 { 0xa8, { 0x20, 0xa8, 0x00 } },
2364 { 0xaa, { 0x61, 0x00 } },
2365 { 0xaf, { 0x20, 0xaf, 0x00 } },
2366 { 0xb2, { 0x32, 0x00 } },
2367 { 0xb3, { 0x33, 0x00 } },
2368 { 0xb4, { 0x20, 0xb4, 0x00 } },
2369 { 0xb8, { 0x20, 0xb8, 0x00 } },
2370 { 0xb9, { 0x31, 0x00 } },
2371 { 0xba, { 0x6f, 0x00 } },
2372 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2373 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2374 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2375 { 0x00 }
2378 if (!pFoldStringA)
2379 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2381 /* these tests are locale specific */
2382 if (GetACP() != 1252)
2384 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2385 return;
2388 /* MAP_FOLDDIGITS */
2389 SetLastError(0);
2390 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2391 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2393 win_skip("FoldStringA is not implemented\n");
2394 return;
2396 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2397 ok(strcmp(dst, digits_dst) == 0,
2398 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2399 for (i = 1; i < 256; i++)
2401 if (!strchr(digits_src, i))
2403 src[0] = i;
2404 src[1] = '\0';
2405 SetLastError(0);
2406 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2407 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2408 ok(dst[0] == src[0],
2409 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2413 /* MAP_EXPAND_LIGATURES */
2414 SetLastError(0);
2415 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2416 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2417 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2418 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2419 ok(strcmp(dst, ligatures_dst) == 0,
2420 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2421 for (i = 1; i < 256; i++)
2423 if (!strchr(ligatures_src, i))
2425 src[0] = i;
2426 src[1] = '\0';
2427 SetLastError(0);
2428 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2429 if (ret == 3)
2431 /* Vista */
2432 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2433 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2434 "Got %s for %d\n", dst, i);
2436 else
2438 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2439 ok(dst[0] == src[0],
2440 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2446 /* MAP_COMPOSITE */
2447 SetLastError(0);
2448 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2450 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2451 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2452 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2454 for (i = 1; i < 256; i++)
2456 if (!strchr(composite_src, i))
2458 src[0] = i;
2459 src[1] = '\0';
2460 SetLastError(0);
2461 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2462 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2463 ok(dst[0] == src[0],
2464 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2465 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2469 /* MAP_FOLDCZONE */
2470 for (i = 1; i < 256; i++)
2472 src[0] = i;
2473 src[1] = '\0';
2474 SetLastError(0);
2475 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2476 is_special = FALSE;
2477 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2479 if (foldczone_special[j].src == src[0])
2481 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2482 "Expected ret == 2 or %d, got %d, error %d\n",
2483 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2484 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2485 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2486 (unsigned char)src[0]);
2487 is_special = TRUE;
2490 if (! is_special)
2492 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2493 ok(src[0] == dst[0],
2494 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2495 (unsigned char)src[0], (unsigned char)dst[0]);
2499 /* MAP_PRECOMPOSED */
2500 for (i = 1; i < 256; i++)
2502 src[0] = i;
2503 src[1] = '\0';
2504 SetLastError(0);
2505 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2506 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2507 ok(src[0] == dst[0],
2508 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2509 (unsigned char)src[0], (unsigned char)dst[0]);
2513 static void test_FoldStringW(void)
2515 int ret;
2516 unsigned int i, j;
2517 WCHAR src[256], dst[256], ch, prev_ch = 1;
2518 static const DWORD badFlags[] =
2521 MAP_PRECOMPOSED|MAP_COMPOSITE,
2522 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2523 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2525 /* Ranges of digits 0-9 : Must be sorted! */
2526 static const WCHAR digitRanges[] =
2528 0x0030, /* '0'-'9' */
2529 0x0660, /* Eastern Arabic */
2530 0x06F0, /* Arabic - Hindu */
2531 0x07C0, /* Nko */
2532 0x0966, /* Devengari */
2533 0x09E6, /* Bengalii */
2534 0x0A66, /* Gurmukhi */
2535 0x0AE6, /* Gujarati */
2536 0x0B66, /* Oriya */
2537 0x0BE6, /* Tamil - No 0 */
2538 0x0C66, /* Telugu */
2539 0x0CE6, /* Kannada */
2540 0x0D66, /* Maylayalam */
2541 0x0DE6, /* Sinhala Lith */
2542 0x0E50, /* Thai */
2543 0x0ED0, /* Laos */
2544 0x0F20, /* Tibet */
2545 0x0F29, /* Tibet half - 0 is out of sequence */
2546 0x1040, /* Myanmar */
2547 0x1090, /* Myanmar Shan */
2548 0x1368, /* Ethiopic - no 0 */
2549 0x17E0, /* Khmer */
2550 0x1810, /* Mongolian */
2551 0x1946, /* Limbu */
2552 0x19D0, /* New Tai Lue */
2553 0x1A80, /* Tai Tham Hora */
2554 0x1A90, /* Tai Tham Tham */
2555 0x1B50, /* Balinese */
2556 0x1BB0, /* Sundanese */
2557 0x1C40, /* Lepcha */
2558 0x1C50, /* Ol Chiki */
2559 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2560 0x2080, /* Subscript */
2561 0x245F, /* Circled - 0 is out of sequence */
2562 0x2473, /* Bracketed */
2563 0x2487, /* Full stop */
2564 0x24F4, /* Double Circled */
2565 0x2775, /* Inverted circled - No 0 */
2566 0x277F, /* Patterned circled - No 0 */
2567 0x2789, /* Inverted Patterned circled - No 0 */
2568 0x3020, /* Hangzhou */
2569 0xA620, /* Vai */
2570 0xA8D0, /* Saurashtra */
2571 0xA900, /* Kayah Li */
2572 0xA9D0, /* Javanese */
2573 0xA9F0, /* Myanmar Tai Laing */
2574 0xAA50, /* Cham */
2575 0xABF0, /* Meetei Mayek */
2576 0xff10, /* Pliene chasse (?) */
2577 0xffff /* Terminator */
2579 /* Digits which are represented, but out of sequence */
2580 static const WCHAR outOfSequenceDigits[] =
2582 0xB9, /* Superscript 1 */
2583 0xB2, /* Superscript 2 */
2584 0xB3, /* Superscript 3 */
2585 0x0C78, /* Telugu Fraction 0 */
2586 0x0C79, /* Telugu Fraction 1 */
2587 0x0C7A, /* Telugu Fraction 2 */
2588 0x0C7B, /* Telugu Fraction 3 */
2589 0x0C7C, /* Telugu Fraction 1 */
2590 0x0C7D, /* Telugu Fraction 2 */
2591 0x0C7E, /* Telugu Fraction 3 */
2592 0x0F33, /* Tibetan half zero */
2593 0x19DA, /* New Tai Lue Tham 1 */
2594 0x24EA, /* Circled 0 */
2595 0x24FF, /* Negative Circled 0 */
2596 0x3007, /* Ideographic number zero */
2597 '\0' /* Terminator */
2599 /* Digits in digitRanges for which no representation is available */
2600 static const WCHAR noDigitAvailable[] =
2602 0x0BE6, /* No Tamil 0 */
2603 0x0F29, /* No Tibetan half zero (out of sequence) */
2604 0x1368, /* No Ethiopic 0 */
2605 0x2473, /* No Bracketed 0 */
2606 0x2487, /* No 0 Full stop */
2607 0x24F4, /* No double circled 0 */
2608 0x2775, /* No inverted circled 0 */
2609 0x277F, /* No patterned circled */
2610 0x2789, /* No inverted Patterned circled */
2611 0x3020, /* No Hangzhou 0 */
2612 '\0' /* Terminator */
2614 static const WCHAR foldczone_src[] =
2616 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2617 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2619 static const WCHAR foldczone_dst[] =
2621 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2623 static const WCHAR foldczone_todo_src[] =
2625 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2627 static const WCHAR foldczone_todo_dst[] =
2629 0x3cb,0x1f0,' ','a',0
2631 static const WCHAR foldczone_todo_broken_dst[] =
2633 0x3cb,0x1f0,0xa0,0xaa,0
2635 static const WCHAR ligatures_src[] =
2637 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2638 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2639 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2640 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2641 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2642 0xfb04, 0xfb05, 0xfb06, '\0'
2644 static const WCHAR ligatures_dst[] =
2646 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2647 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2648 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2649 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2650 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2651 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2654 if (!pFoldStringW)
2656 win_skip("FoldStringW is not available\n");
2657 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2660 /* Invalid flag combinations */
2661 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2663 src[0] = dst[0] = '\0';
2664 SetLastError(0);
2665 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2666 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2668 win_skip("FoldStringW is not implemented\n");
2669 return;
2671 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2672 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2675 /* src & dst cannot be the same */
2676 SetLastError(0);
2677 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2678 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2679 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2681 /* src can't be NULL */
2682 SetLastError(0);
2683 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2684 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2685 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2687 /* srclen can't be 0 */
2688 SetLastError(0);
2689 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2690 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2691 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2693 /* dstlen can't be < 0 */
2694 SetLastError(0);
2695 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2696 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2697 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2699 /* Ret includes terminating NUL which is appended if srclen = -1 */
2700 SetLastError(0);
2701 src[0] = 'A';
2702 src[1] = '\0';
2703 dst[0] = '\0';
2704 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2705 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2706 ok(dst[0] == 'A' && dst[1] == '\0',
2707 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2708 'A', '\0', ret, dst[0], dst[1], GetLastError());
2710 /* If size is given, result is not NUL terminated */
2711 SetLastError(0);
2712 src[0] = 'A';
2713 src[1] = 'A';
2714 dst[0] = 'X';
2715 dst[1] = 'X';
2716 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2717 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2718 ok(dst[0] == 'A' && dst[1] == 'X',
2719 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2720 'A','X', ret, dst[0], dst[1], GetLastError());
2722 /* MAP_FOLDDIGITS */
2723 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2725 /* Check everything before this range */
2726 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2728 SetLastError(0);
2729 src[0] = ch;
2730 src[1] = dst[0] = '\0';
2731 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2732 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2734 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2735 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
2736 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
2737 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
2738 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
2739 "char %04x should not be a digit\n", ch );
2742 if (digitRanges[j] == 0xffff)
2743 break; /* Finished the whole code point space */
2745 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2747 WCHAR c;
2749 /* Map out of sequence characters */
2750 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2751 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2752 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2753 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2754 else c = ch;
2755 SetLastError(0);
2756 src[0] = c;
2757 src[1] = dst[0] = '\0';
2758 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2759 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2761 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2762 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2763 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2764 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2765 strchrW(noDigitAvailable, c),
2766 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
2767 ch, '0' + digitRanges[j] - ch, dst[0]);
2769 prev_ch = ch;
2772 /* MAP_FOLDCZONE */
2773 SetLastError(0);
2774 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2775 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2776 "Got %d, error %d\n", ret, GetLastError());
2777 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2778 "MAP_FOLDCZONE: Expanded incorrectly\n");
2780 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2781 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2782 "Got %d, error %d\n", ret, GetLastError());
2783 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2784 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2785 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2787 /* MAP_EXPAND_LIGATURES */
2788 SetLastError(0);
2789 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2790 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2791 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2792 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2793 "Got %d, error %d\n", ret, GetLastError());
2794 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2795 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2798 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2803 #define LCID_OK(l) \
2804 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2805 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2806 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2807 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2808 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2810 static void test_ConvertDefaultLocale(void)
2812 LCID lcid;
2814 /* Doesn't change lcid, even if non default sublang/sort used */
2815 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2816 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2817 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2818 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2820 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2821 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2822 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2823 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2824 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2826 /* Invariant language is not treated specially */
2827 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2829 /* User/system default languages alone are not mapped */
2830 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2831 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2833 /* Default lcids */
2834 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2835 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2836 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2839 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2840 DWORD dwFlags, LONG_PTR lParam)
2842 trace("%08x, %s, %s, %08x, %08lx\n",
2843 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2845 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2846 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2848 /* If lParam is one, we are calling with flags defaulted from 0 */
2849 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2850 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2852 return TRUE;
2855 static void test_EnumSystemLanguageGroupsA(void)
2857 BOOL ret;
2859 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2861 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2862 return;
2865 /* No enumeration proc */
2866 SetLastError(0);
2867 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2868 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2870 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2871 return;
2873 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2874 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2876 /* Invalid flags */
2877 SetLastError(0);
2878 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2879 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2881 /* No flags - defaults to LGRPID_INSTALLED */
2882 SetLastError(0xdeadbeef);
2883 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2884 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2886 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2887 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2890 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2892 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2893 return TRUE;
2896 static void test_EnumSystemLocalesEx(void)
2898 BOOL ret;
2900 if (!pEnumSystemLocalesEx)
2902 win_skip( "EnumSystemLocalesEx not available\n" );
2903 return;
2905 SetLastError( 0xdeadbeef );
2906 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2907 ok( !ret, "should have failed\n" );
2908 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2909 SetLastError( 0xdeadbeef );
2910 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2911 ok( ret, "failed err %u\n", GetLastError() );
2914 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2915 LONG_PTR lParam)
2917 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2919 /* invalid locale enumerated on some platforms */
2920 if (lcid == 0)
2921 return TRUE;
2923 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2924 "Enumerated grp %d not valid\n", lgrpid);
2925 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2926 "Enumerated grp locale %04x not valid\n", lcid);
2927 return TRUE;
2930 static void test_EnumLanguageGroupLocalesA(void)
2932 BOOL ret;
2934 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2936 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2937 return;
2940 /* No enumeration proc */
2941 SetLastError(0);
2942 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2943 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2945 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2946 return;
2948 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2949 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2951 /* lgrpid too small */
2952 SetLastError(0);
2953 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2954 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2955 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2957 /* lgrpid too big */
2958 SetLastError(0);
2959 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2960 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2961 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2963 /* dwFlags is reserved */
2964 SetLastError(0);
2965 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2966 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2967 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2969 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2972 static void test_SetLocaleInfoA(void)
2974 BOOL bRet;
2975 LCID lcid = GetUserDefaultLCID();
2977 /* Null data */
2978 SetLastError(0);
2979 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2980 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2981 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2983 /* IDATE */
2984 SetLastError(0);
2985 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2986 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2987 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2989 /* ILDATE */
2990 SetLastError(0);
2991 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2992 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2993 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2996 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2998 trace("%s %08lx\n", value, lParam);
2999 return(TRUE);
3002 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3004 ok(!enumCount, "callback called again unexpected\n");
3005 enumCount++;
3006 return(FALSE);
3009 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3011 ok(0,"callback called unexpected\n");
3012 return(FALSE);
3015 static void test_EnumUILanguageA(void)
3017 BOOL ret;
3018 if (!pEnumUILanguagesA) {
3019 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3020 return;
3023 SetLastError(ERROR_SUCCESS);
3024 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3025 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3027 win_skip("EnumUILanguagesA is not implemented\n");
3028 return;
3030 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3032 enumCount = 0;
3033 SetLastError(ERROR_SUCCESS);
3034 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3037 SetLastError(ERROR_SUCCESS);
3038 ret = pEnumUILanguagesA(NULL, 0, 0);
3039 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3040 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3041 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3043 SetLastError(ERROR_SUCCESS);
3044 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3045 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3046 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3048 SetLastError(ERROR_SUCCESS);
3049 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3050 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3051 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3052 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3055 static char date_fmt_buf[1024];
3057 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3059 lstrcatA(date_fmt_buf, fmt);
3060 lstrcatA(date_fmt_buf, "\n");
3061 return TRUE;
3064 static void test_EnumDateFormatsA(void)
3066 char *p, buf[256];
3067 BOOL ret;
3068 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3070 date_fmt_buf[0] = 0;
3071 SetLastError(0xdeadbeef);
3072 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3073 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3075 win_skip("0 for dwFlags is not supported\n");
3077 else
3079 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3080 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3081 /* test the 1st enumerated format */
3082 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3083 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3084 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3085 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3088 date_fmt_buf[0] = 0;
3089 SetLastError(0xdeadbeef);
3090 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3091 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3093 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3095 else
3097 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3098 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3099 /* test the 1st enumerated format */
3100 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3101 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3102 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3103 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3106 date_fmt_buf[0] = 0;
3107 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3108 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3109 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3110 /* test the 1st enumerated format */
3111 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3112 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3113 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3114 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3116 date_fmt_buf[0] = 0;
3117 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3118 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3119 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3120 /* test the 1st enumerated format */
3121 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3122 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3123 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3124 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3126 date_fmt_buf[0] = 0;
3127 SetLastError(0xdeadbeef);
3128 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3129 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3131 skip("DATE_YEARMONTH is only present on W2K and later\n");
3132 return;
3134 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3135 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3136 /* test the 1st enumerated format */
3137 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3138 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3139 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3140 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3141 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3144 static void test_EnumTimeFormatsA(void)
3146 char *p, buf[256];
3147 BOOL ret;
3148 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3150 date_fmt_buf[0] = 0;
3151 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3152 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3153 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3154 /* test the 1st enumerated format */
3155 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3156 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3157 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3158 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3160 date_fmt_buf[0] = 0;
3161 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3162 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3163 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3164 /* test the 1st enumerated format */
3165 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3166 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3167 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3168 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3171 static void test_GetCPInfo(void)
3173 BOOL ret;
3174 CPINFO cpinfo;
3176 SetLastError(0xdeadbeef);
3177 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3178 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3179 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3180 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3182 SetLastError(0xdeadbeef);
3183 ret = GetCPInfo(CP_UTF7, &cpinfo);
3184 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3186 skip("Codepage CP_UTF7 is not installed/available\n");
3188 else
3190 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3191 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3192 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3193 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3194 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3195 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3198 SetLastError(0xdeadbeef);
3199 ret = GetCPInfo(CP_UTF8, &cpinfo);
3200 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3202 skip("Codepage CP_UTF8 is not installed/available\n");
3204 else
3206 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3207 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3208 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3209 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3210 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3211 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3212 "expected 4, got %u\n", cpinfo.MaxCharSize);
3217 * The CT_TYPE1 has varied over windows version.
3218 * The current target for correct behavior is windows 7.
3219 * There was a big shift between windows 2000 (first introduced) and windows Xp
3220 * Most of the old values below are from windows 2000.
3221 * A smaller subset of changes happened between windows Xp and Window vista/7
3223 static void test_GetStringTypeW(void)
3225 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3226 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3227 C1_SPACE | C1_BLANK | C1_DEFINED,
3228 C1_SPACE | C1_BLANK | C1_DEFINED,
3229 C1_SPACE | C1_BLANK | C1_DEFINED,
3230 C1_CNTRL | C1_BLANK | C1_DEFINED};
3231 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3232 C1_SPACE | C1_BLANK,
3233 C1_SPACE | C1_BLANK,
3234 C1_SPACE | C1_BLANK,
3235 C1_SPACE | C1_BLANK};
3237 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3239 /* Lu, Ll, Lt */
3240 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3241 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3242 C1_LOWER | C1_ALPHA,
3243 C1_UPPER | C1_LOWER | C1_ALPHA,
3244 C1_ALPHA};
3246 /* Sk, Sk, Mn, So, Me */
3247 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3248 /* Sc, Sm, No,*/
3249 0xffe0, 0xffe9, 0x2153};
3251 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3252 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3253 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3254 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3255 C1_ALPHA | C1_DEFINED,
3256 C1_CNTRL | C1_DEFINED,
3257 C1_PUNCT | C1_DEFINED,
3258 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3259 C1_ALPHA | C1_LOWER | C1_DEFINED,
3260 C1_ALPHA | C1_DEFINED };
3261 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3262 C1_ALPHA | C1_DEFINED,
3263 C1_CNTRL | C1_DEFINED,
3264 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3265 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3266 C1_ALPHA | C1_DEFINED,
3267 C1_DEFINED
3269 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3270 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3272 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3273 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3274 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3275 static const WCHAR lower_special[] = {0x2071, 0x207f};
3276 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3277 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3278 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3279 0xfff9, 0xfffa, 0xfffb};
3280 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3282 WORD types[20];
3283 WCHAR ch;
3284 int i;
3286 memset(types,0,sizeof(types));
3287 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3288 for (i = 0; i < 5; i++)
3289 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]);
3291 memset(types,0,sizeof(types));
3292 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3293 for (i = 0; i < 3; i++)
3294 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]));
3295 memset(types,0,sizeof(types));
3296 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3297 for (i = 0; i < 5; i++)
3298 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3300 memset(types,0,sizeof(types));
3301 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3302 for (i = 0; i < 8; i++)
3303 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);
3305 memset(types,0,sizeof(types));
3306 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3307 for (i = 0; i < 7; i++)
3308 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]);
3310 memset(types,0,sizeof(types));
3311 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3312 for (i = 0; i < 7; i++)
3313 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));
3316 memset(types,0,sizeof(types));
3317 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3318 for (i = 0; i < 12; i++)
3319 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);
3321 memset(types,0,sizeof(types));
3322 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3323 for (i = 0; i < 3; i++)
3324 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);
3326 memset(types,0,sizeof(types));
3327 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3328 for (i = 0; i < 2; i++)
3329 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);
3331 memset(types,0,sizeof(types));
3332 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3333 for (i = 0; i < 20; i++)
3334 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);
3336 memset(types,0,sizeof(types));
3337 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3338 for (i = 0; i < 3; i++)
3339 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 );
3341 /* surrogate pairs */
3342 ch = 0xd800;
3343 memset(types, 0, sizeof(types));
3344 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3345 if (types[0] == C3_NOTAPPLICABLE)
3346 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
3347 else {
3348 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
3350 ch = 0xdc00;
3351 memset(types, 0, sizeof(types));
3352 GetStringTypeW(CT_CTYPE3, &ch, 1, types);
3353 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
3357 static void test_IdnToNameprepUnicode(void)
3359 struct {
3360 DWORD in_len;
3361 const WCHAR in[64];
3362 DWORD ret;
3363 DWORD broken_ret;
3364 const WCHAR out[64];
3365 DWORD flags;
3366 DWORD err;
3367 DWORD todo;
3368 } test_data[] = {
3370 5, {'t','e','s','t',0},
3371 5, 5, {'t','e','s','t',0},
3372 0, 0xdeadbeef
3375 3, {'a',0xe111,'b'},
3376 0, 0, {0},
3377 0, ERROR_INVALID_NAME
3380 4, {'t',0,'e',0},
3381 0, 0, {0},
3382 0, ERROR_INVALID_NAME
3385 1, {'T',0},
3386 1, 1, {'T',0},
3387 0, 0xdeadbeef
3390 1, {0},
3391 0, 0, {0},
3392 0, ERROR_INVALID_NAME
3395 6, {' ','-','/','[',']',0},
3396 6, 6, {' ','-','/','[',']',0},
3397 0, 0xdeadbeef
3400 3, {'a','-','a'},
3401 3, 3, {'a','-','a'},
3402 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3405 3, {'a','a','-'},
3406 0, 0, {0},
3407 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3409 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3410 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3411 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3412 0, 0xdeadbeef, TRUE
3415 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3416 2, 0, {'t',0},
3417 0, 0xdeadbeef
3419 { /* Another example of incorrectly working FoldString (composition) */
3420 2, {0x3b0, 0},
3421 2, 2, {0x3b0, 0},
3422 0, 0xdeadbeef, TRUE
3425 2, {0x221, 0},
3426 0, 2, {0},
3427 0, ERROR_NO_UNICODE_TRANSLATION
3430 2, {0x221, 0},
3431 2, 2, {0x221, 0},
3432 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3435 5, {'a','.','.','a',0},
3436 0, 0, {0},
3437 0, ERROR_INVALID_NAME
3440 3, {'a','.',0},
3441 3, 3, {'a','.',0},
3442 0, 0xdeadbeef
3446 WCHAR buf[1024];
3447 DWORD i, ret, err;
3449 if (!pIdnToNameprepUnicode)
3451 win_skip("IdnToNameprepUnicode is not available\n");
3452 return;
3455 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3456 test_data[0].in_len, NULL, 0);
3457 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3459 SetLastError(0xdeadbeef);
3460 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3461 test_data[1].in_len, NULL, 0);
3462 err = GetLastError();
3463 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3464 ok(err == test_data[1].err, "err = %d\n", err);
3466 SetLastError(0xdeadbeef);
3467 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3468 buf, sizeof(buf)/sizeof(WCHAR));
3469 err = GetLastError();
3470 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3471 ok(err == 0xdeadbeef, "err = %d\n", err);
3473 SetLastError(0xdeadbeef);
3474 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3475 buf, sizeof(buf)/sizeof(WCHAR));
3476 err = GetLastError();
3477 ok(ret == 0, "ret = %d\n", ret);
3478 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3480 SetLastError(0xdeadbeef);
3481 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3482 buf, sizeof(buf)/sizeof(WCHAR));
3483 err = GetLastError();
3484 ok(ret == 0, "ret = %d\n", ret);
3485 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3487 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3488 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3489 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3491 SetLastError(0xdeadbeef);
3492 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3493 err = GetLastError();
3494 ok(ret == 0, "ret = %d\n", ret);
3495 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3497 SetLastError(0xdeadbeef);
3498 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3499 err = GetLastError();
3500 ok(ret == 0, "ret = %d\n", ret);
3501 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
3502 "err = %d\n", err);
3504 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3506 SetLastError(0xdeadbeef);
3507 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3508 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3509 err = GetLastError();
3511 if (!test_data[i].todo)
3513 ok(ret == test_data[i].ret ||
3514 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3516 else
3518 todo_wine ok(ret == test_data[i].ret ||
3519 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
3521 if(ret != test_data[i].ret)
3522 continue;
3524 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3525 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3526 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3530 static void test_IdnToAscii(void)
3532 struct {
3533 DWORD in_len;
3534 const WCHAR in[64];
3535 DWORD ret;
3536 const WCHAR out[64];
3537 DWORD flags;
3538 DWORD err;
3539 } test_data[] = {
3541 5, {'T','e','s','t',0},
3542 5, {'T','e','s','t',0},
3543 0, 0xdeadbeef
3546 5, {'T','e',0x017c,'s','t',0},
3547 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3548 0, 0xdeadbeef
3551 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3552 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3553 0, 0xdeadbeef
3556 3, {0x0105,'.',0},
3557 9, {'x','n','-','-','2','d','a','.',0},
3558 0, 0xdeadbeef
3561 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3562 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3563 0, 0xdeadbeef
3566 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3567 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3568 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3569 0, 0xdeadbeef
3572 2, {0x221,0},
3573 8, {'x','n','-','-','6','l','a',0},
3574 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3578 WCHAR buf[1024];
3579 DWORD i, ret, err;
3581 if (!pIdnToAscii)
3583 win_skip("IdnToAscii is not available\n");
3584 return;
3587 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3589 SetLastError(0xdeadbeef);
3590 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3591 test_data[i].in_len, buf, sizeof(buf));
3592 err = GetLastError();
3593 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3594 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3595 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3596 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3600 static void test_IdnToUnicode(void)
3602 struct {
3603 DWORD in_len;
3604 const WCHAR in[64];
3605 DWORD ret;
3606 const WCHAR out[64];
3607 DWORD flags;
3608 DWORD err;
3609 } test_data[] = {
3611 5, {'T','e','s','.',0},
3612 5, {'T','e','s','.',0},
3613 0, 0xdeadbeef
3616 2, {0x105,0},
3617 0, {0},
3618 0, ERROR_INVALID_NAME
3621 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3622 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3623 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3624 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3625 0x05d1,0x05e8,0x05d9,0x05ea,0},
3626 0, 0xdeadbeef
3629 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3630 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3631 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3632 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3633 0, 0xdeadbeef
3636 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3637 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3638 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3639 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3640 0, {0},
3641 0, ERROR_INVALID_NAME
3644 8, {'x','n','-','-','6','l','a',0},
3645 2, {0x221,0},
3646 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3650 WCHAR buf[1024];
3651 DWORD i, ret, err;
3653 if (!pIdnToUnicode)
3655 win_skip("IdnToUnicode is not available\n");
3656 return;
3659 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3661 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3662 test_data[i].in_len, NULL, 0);
3663 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3665 SetLastError(0xdeadbeef);
3666 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3667 test_data[i].in_len, buf, sizeof(buf));
3668 err = GetLastError();
3669 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3670 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3671 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3672 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3676 static void test_GetLocaleInfoEx(void)
3678 static const WCHAR enW[] = {'e','n',0};
3679 WCHAR bufferW[80];
3680 INT ret;
3682 if (!pGetLocaleInfoEx)
3684 win_skip("GetLocaleInfoEx not supported\n");
3685 return;
3688 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3689 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3690 if (ret)
3692 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3693 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3694 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3695 static const WCHAR usaW[] = {'U','S','A',0};
3696 static const WCHAR enuW[] = {'E','N','U',0};
3697 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3698 DWORD val;
3700 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3701 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3703 SetLastError(0xdeadbeef);
3704 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
3705 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
3707 SetLastError(0xdeadbeef);
3708 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
3709 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
3711 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3712 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3713 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3715 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3716 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3717 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3719 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3720 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3721 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3723 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3724 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3725 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
3726 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
3728 skip("Non-English locale\n");
3730 else
3731 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3733 bufferW[0] = 0;
3734 SetLastError(0xdeadbeef);
3735 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3736 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3738 while (*ptr->name)
3740 val = 0;
3741 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3742 if (ptr->todo)
3743 todo_wine
3744 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3745 else
3746 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3747 bufferW[0] = 0;
3748 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3749 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
3750 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3751 ptr++;
3756 static void test_IsValidLocaleName(void)
3758 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3759 static const WCHAR zzW[] = {'z','z',0};
3760 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3761 BOOL ret;
3763 if (!pIsValidLocaleName)
3765 win_skip("IsValidLocaleName not supported\n");
3766 return;
3769 ret = pIsValidLocaleName(enusW);
3770 ok(ret, "IsValidLocaleName failed\n");
3771 ret = pIsValidLocaleName(zzW);
3772 ok(!ret, "IsValidLocaleName should have failed\n");
3773 ret = pIsValidLocaleName(zzzzW);
3774 ok(!ret, "IsValidLocaleName should have failed\n");
3777 static void test_CompareStringOrdinal(void)
3779 INT ret;
3780 WCHAR test1[] = { 't','e','s','t',0 };
3781 WCHAR test2[] = { 'T','e','S','t',0 };
3782 WCHAR test3[] = { 't','e','s','t','3',0 };
3783 WCHAR null1[] = { 'a',0,'a',0 };
3784 WCHAR null2[] = { 'a',0,'b',0 };
3785 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
3786 WCHAR bills2[] = { 'b','i','l','l','s',0 };
3787 WCHAR coop1[] = { 'c','o','-','o','p',0 };
3788 WCHAR coop2[] = { 'c','o','o','p',0 };
3789 WCHAR nonascii1[] = { 0x0102,0 };
3790 WCHAR nonascii2[] = { 0x0201,0 };
3792 if (!pCompareStringOrdinal)
3794 win_skip("CompareStringOrdinal not supported\n");
3795 return;
3798 /* Check errors */
3799 SetLastError(0xdeadbeef);
3800 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
3801 ok(!ret, "Got %u, expected 0\n", ret);
3802 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3803 SetLastError(0xdeadbeef);
3804 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
3805 ok(!ret, "Got %u, expected 0\n", ret);
3806 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3807 SetLastError(0xdeadbeef);
3808 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
3809 ok(!ret, "Got %u, expected 0\n", ret);
3810 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3812 /* Check case */
3813 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
3814 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3815 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
3816 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3817 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
3818 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3819 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
3820 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3822 /* Check different sizes */
3823 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
3824 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3825 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
3826 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3828 /* Check null character */
3829 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
3830 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3831 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
3832 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3833 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
3834 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3835 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
3836 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3838 /* Check ordinal behaviour */
3839 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
3840 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3841 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
3842 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3843 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
3844 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3845 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
3846 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3849 static void test_GetGeoInfo(void)
3851 char buffA[20];
3852 INT ret;
3854 if (!pGetGeoInfoA)
3856 win_skip("GetGeoInfo is not available.\n");
3857 return;
3860 /* unassigned id */
3861 SetLastError(0xdeadbeef);
3862 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
3863 ok(ret == 0, "got %d\n", ret);
3864 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
3866 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
3867 ok(ret == 3, "got %d\n", ret);
3869 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
3870 ok(ret == 4, "got %d\n", ret);
3872 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
3873 ok(ret == 3, "got %d\n", ret);
3874 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
3876 /* buffer pointer not NULL, length is 0 - return required length */
3877 buffA[0] = 'a';
3878 SetLastError(0xdeadbeef);
3879 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
3880 ok(ret == 3, "got %d\n", ret);
3881 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
3883 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
3884 ok(ret == 4, "got %d\n", ret);
3885 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
3887 /* shorter buffer */
3888 SetLastError(0xdeadbeef);
3889 buffA[1] = buffA[2] = 0;
3890 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
3891 ok(ret == 0, "got %d\n", ret);
3892 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
3893 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
3895 /* GEO_NATION returns GEOID in a string form */
3896 buffA[0] = 0;
3897 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
3898 ok(ret == 4, "got %d\n", ret);
3899 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
3901 /* GEO_PARENT */
3902 buffA[0] = 0;
3903 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
3904 if (ret == 0)
3905 win_skip("GEO_PARENT not supported.\n");
3906 else
3908 ok(ret == 6, "got %d\n", ret);
3909 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
3912 buffA[0] = 0;
3913 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
3914 if (ret == 0)
3915 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
3916 else
3918 ok(ret == 4, "got %d\n", ret);
3919 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
3922 /* try invalid type value */
3923 SetLastError(0xdeadbeef);
3924 ret = pGetGeoInfoA(203, GEO_PARENT + 1, NULL, 0, 0);
3925 ok(ret == 0, "got %d\n", ret);
3926 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
3929 static int geoidenum_count;
3930 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
3932 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
3933 ok(ret == 3, "got %d for %d\n", ret, geoid);
3934 /* valid geoid starts at 2 */
3935 ok(geoid >= 2, "got geoid %d\n", geoid);
3937 return geoidenum_count++ < 5;
3940 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
3942 geoidenum_count++;
3943 return TRUE;
3946 static void test_EnumSystemGeoID(void)
3948 BOOL ret;
3950 if (!pEnumSystemGeoID)
3952 win_skip("EnumSystemGeoID is not available.\n");
3953 return;
3956 SetLastError(0xdeadbeef);
3957 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
3958 ok(!ret, "got %d\n", ret);
3959 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
3961 SetLastError(0xdeadbeef);
3962 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
3963 ok(!ret, "got %d\n", ret);
3964 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
3966 SetLastError(0xdeadbeef);
3967 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
3968 ok(!ret, "got %d\n", ret);
3969 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
3971 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
3972 ok(ret, "got %d\n", ret);
3974 /* only first level is enumerated, not the whole hierarchy */
3975 geoidenum_count = 0;
3976 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
3977 if (ret == 0)
3978 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
3979 else
3980 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
3982 geoidenum_count = 0;
3983 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
3984 if (ret == 0)
3985 skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
3986 else
3988 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
3990 geoidenum_count = 0;
3991 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
3992 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
3996 START_TEST(locale)
3998 InitFunctionPointers();
4000 test_EnumTimeFormatsA();
4001 test_EnumDateFormatsA();
4002 test_GetLocaleInfoA();
4003 test_GetLocaleInfoW();
4004 test_GetLocaleInfoEx();
4005 test_GetTimeFormatA();
4006 test_GetDateFormatA();
4007 test_GetDateFormatW();
4008 test_GetCurrencyFormatA(); /* Also tests the W version */
4009 test_GetNumberFormatA(); /* Also tests the W version */
4010 test_CompareStringA();
4011 test_CompareStringEx();
4012 test_LCMapStringA();
4013 test_LCMapStringW();
4014 test_LCMapStringEx();
4015 test_LocaleNameToLCID();
4016 test_FoldStringA();
4017 test_FoldStringW();
4018 test_ConvertDefaultLocale();
4019 test_EnumSystemLanguageGroupsA();
4020 test_EnumSystemLocalesEx();
4021 test_EnumLanguageGroupLocalesA();
4022 test_SetLocaleInfoA();
4023 test_EnumUILanguageA();
4024 test_GetCPInfo();
4025 test_GetStringTypeW();
4026 test_IdnToNameprepUnicode();
4027 test_IdnToAscii();
4028 test_IdnToUnicode();
4029 test_IsValidLocaleName();
4030 test_CompareStringOrdinal();
4031 test_GetGeoInfo();
4032 test_EnumSystemGeoID();
4033 /* this requires collation table patch to make it MS compatible */
4034 if (0) test_sorting();