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