kernel32/tests: Show flags as text in test results.
[wine.git] / dlls / kernel32 / tests / locale.c
blob07d6f8cc7f61e836ea5bed1a70ad8076cb2aecec
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 title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
42 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
43 static const WCHAR localeW[] = {'e','n','-','U','S',0};
44 static const WCHAR fooW[] = {'f','o','o',0};
45 static const WCHAR emptyW[] = {0};
47 static inline unsigned int strlenW( const WCHAR *str )
49 const WCHAR *s = str;
50 while (*s) s++;
51 return s - str;
54 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
56 if (n <= 0) return 0;
57 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
58 return *str1 - *str2;
61 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
63 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
64 return NULL;
67 static inline BOOL isdigitW( WCHAR wc )
69 WORD type;
70 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
71 return type & C1_DIGIT;
74 /* Some functions are only in later versions of kernel32.dll */
75 static WORD enumCount;
77 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
78 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
79 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
80 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
83 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
84 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
85 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
86 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
87 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
89 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
90 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
93 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
94 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
95 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
96 LPNLSVERSIONINFO, LPVOID, LPARAM);
97 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
98 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
99 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
100 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
101 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
103 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
104 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
106 static void InitFunctionPointers(void)
108 HMODULE mod = GetModuleHandleA("kernel32");
110 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
111 X(GetTimeFormatEx);
112 X(GetDateFormatEx);
113 X(EnumSystemLanguageGroupsA);
114 X(EnumLanguageGroupLocalesA);
115 X(LocaleNameToLCID);
116 X(LCIDToLocaleName);
117 X(LCMapStringEx);
118 X(FoldStringA);
119 X(FoldStringW);
120 X(IsValidLanguageGroup);
121 X(EnumUILanguagesA);
122 X(EnumSystemLocalesEx);
123 X(IdnToNameprepUnicode);
124 X(IdnToAscii);
125 X(IdnToUnicode);
126 X(GetLocaleInfoEx);
127 X(IsValidLocaleName);
128 X(CompareStringOrdinal);
129 X(CompareStringEx);
130 X(GetGeoInfoA);
131 X(GetGeoInfoW);
132 X(EnumSystemGeoID);
133 X(GetSystemPreferredUILanguages);
134 X(GetThreadPreferredUILanguages);
135 X(GetUserPreferredUILanguages);
136 X(GetNumberFormatEx);
138 mod = GetModuleHandleA("ntdll");
139 X(RtlUpcaseUnicodeChar);
140 #undef X
143 #define eq(received, expected, label, type) \
144 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
145 (label), (received), (expected))
147 #define BUFFER_SIZE 128
148 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
150 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
151 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
152 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
153 "Expected '%s', got '%s'\n", Expected, buffer)
155 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
156 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
157 SetLastError(0xdeadbeef); buffer[0] = '\0'
158 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
159 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
161 #define NUO LOCALE_NOUSEROVERRIDE
163 static void test_GetLocaleInfoA(void)
165 int ret;
166 int len;
167 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
168 char buffer[BUFFER_SIZE];
169 char expected[BUFFER_SIZE];
170 DWORD val;
172 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
174 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
175 ok(ret, "got %d\n", ret);
176 ok(val == lcid, "got 0x%08x\n", val);
178 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
179 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
180 assumes SUBLANG_NEUTRAL for zh */
181 memset(expected, 0, COUNTOF(expected));
182 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
183 SetLastError(0xdeadbeef);
184 memset(buffer, 0, COUNTOF(buffer));
185 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
186 ok((ret == len) && !lstrcmpA(buffer, expected),
187 "got %d with '%s' (expected %d with '%s')\n",
188 ret, buffer, len, expected);
190 memset(expected, 0, COUNTOF(expected));
191 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
192 if (len) {
193 SetLastError(0xdeadbeef);
194 memset(buffer, 0, COUNTOF(buffer));
195 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
196 ok((ret == len) && !lstrcmpA(buffer, expected),
197 "got %d with '%s' (expected %d with '%s')\n",
198 ret, buffer, len, expected);
200 else
201 win_skip("LANG_ARABIC not installed\n");
203 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
204 memset(expected, 0, COUNTOF(expected));
205 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
206 SetLastError(0xdeadbeef);
207 memset(buffer, 0, COUNTOF(buffer));
208 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
209 ok((ret == len) && !lstrcmpA(buffer, expected),
210 "got %d with '%s' (expected %d with '%s')\n",
211 ret, buffer, len, expected);
214 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
215 * partially fill the buffer even if it is too short. See bug 637.
217 SetLastError(0xdeadbeef);
218 memset(buffer, 0, COUNTOF(buffer));
219 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
220 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
222 SetLastError(0xdeadbeef);
223 memset(buffer, 0, COUNTOF(buffer));
224 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
225 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
226 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
227 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
229 SetLastError(0xdeadbeef);
230 memset(buffer, 0, COUNTOF(buffer));
231 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
232 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
233 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
236 struct neutralsublang_name2_t {
237 WCHAR name[3];
238 WCHAR sname[15];
239 LCID lcid;
240 LCID lcid_broken;
241 WCHAR sname_broken[15];
242 int todo;
245 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
246 { {'a','r',0}, {'a','r','-','S','A',0},
247 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
248 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
249 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
250 { {'d','e',0}, {'d','e','-','D','E',0},
251 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
252 { {'e','n',0}, {'e','n','-','U','S',0},
253 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
254 { {'e','s',0}, {'e','s','-','E','S',0},
255 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
256 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
257 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
258 { {'g','a',0}, {'g','a','-','I','E',0},
259 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
260 { {'i','t',0}, {'i','t','-','I','T',0},
261 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
262 { {'m','s',0}, {'m','s','-','M','Y',0},
263 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
264 { {'n','l',0}, {'n','l','-','N','L',0},
265 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
266 { {'p','t',0}, {'p','t','-','B','R',0},
267 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
268 { {'s','r',0}, {'h','r','-','H','R',0},
269 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
270 { {'s','v',0}, {'s','v','-','S','E',0},
271 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
272 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
273 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
274 { {'z','h',0}, {'z','h','-','C','N',0},
275 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
276 { {0} }
279 static void test_GetLocaleInfoW(void)
281 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
282 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
283 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
284 WCHAR bufferW[80], buffer2W[80];
285 CHAR bufferA[80];
286 DWORD val;
287 DWORD ret;
288 INT i;
290 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
291 if (!ret) {
292 win_skip("GetLocaleInfoW() isn't implemented\n");
293 return;
296 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
297 ok(ret, "got %d\n", ret);
298 ok(val == lcid_en, "got 0x%08x\n", val);
300 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
301 if (ret)
303 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
304 'S','t','a','t','e','s',')',0};
305 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
306 static const WCHAR enW[] = {'e','n','-','U','S',0};
307 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
309 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
311 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
312 ok(ret, "got %d\n", ret);
313 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
314 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
316 skip("Non-English locale\n");
318 else
319 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
321 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
322 ok(ret, "got %d\n", ret);
323 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
324 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
326 skip("Non-English locale\n");
328 else
329 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
331 while (*ptr->name)
333 LANGID langid;
334 LCID lcid;
336 /* make neutral lcid */
337 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
338 lcid = MAKELCID(langid, SORT_DEFAULT);
340 val = 0;
341 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
342 todo_wine_if (ptr->todo & 0x1)
343 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
344 wine_dbgstr_w(ptr->name), val, ptr->lcid);
346 /* now check LOCALE_SNAME */
347 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
348 todo_wine_if (ptr->todo & 0x2)
349 ok(!lstrcmpW(bufferW, ptr->sname) ||
350 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
351 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
352 ptr++;
355 else
356 win_skip("English neutral locale not supported\n");
358 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
359 if (!ret) {
360 win_skip("LANG_RUSSIAN locale data unavailable\n");
361 return;
363 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
364 bufferW, COUNTOF(bufferW));
365 if (!ret) {
366 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
367 return;
370 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
371 bufferA[0] = 'a';
372 SetLastError(0xdeadbeef);
373 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
374 bufferA, COUNTOF(bufferA));
375 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
376 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
377 ok(GetLastError() == ERROR_INVALID_FLAGS,
378 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
380 bufferW[0] = 'a';
381 SetLastError(0xdeadbeef);
382 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
383 bufferW, COUNTOF(bufferW));
384 ok(ret == 0,
385 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
386 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
387 ok(GetLastError() == ERROR_INVALID_FLAGS,
388 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
390 /* yes, test empty 13 month entry too */
391 for (i = 0; i < 12; i++) {
392 bufferW[0] = 0;
393 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
394 bufferW, COUNTOF(bufferW));
395 ok(ret, "Expected non zero result\n");
396 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
397 ret, lstrlenW(bufferW));
398 buffer2W[0] = 0;
399 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
400 buffer2W, COUNTOF(buffer2W));
401 ok(ret, "Expected non zero result\n");
402 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
403 ret, lstrlenW(buffer2W));
405 ok(lstrcmpW(bufferW, buffer2W) != 0,
406 "Expected genitive name to differ, got the same for month %d\n", i+1);
408 /* for locale without genitive names nominative returned in both cases */
409 bufferW[0] = 0;
410 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
411 bufferW, COUNTOF(bufferW));
412 ok(ret, "Expected non zero result\n");
413 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
414 ret, lstrlenW(bufferW));
415 buffer2W[0] = 0;
416 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
417 buffer2W, COUNTOF(buffer2W));
418 ok(ret, "Expected non zero result\n");
419 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
420 ret, lstrlenW(buffer2W));
422 ok(lstrcmpW(bufferW, buffer2W) == 0,
423 "Expected same names, got different for month %d\n", i+1);
427 static void test_GetTimeFormatA(void)
429 int ret;
430 SYSTEMTIME curtime;
431 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
432 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
434 memset(&curtime, 2, sizeof(SYSTEMTIME));
435 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
436 SetLastError(0xdeadbeef);
437 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
438 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
439 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
441 curtime.wHour = 8;
442 curtime.wMinute = 56;
443 curtime.wSecond = 13;
444 curtime.wMilliseconds = 22;
445 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
446 SetLastError(0xdeadbeef);
447 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
448 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
449 EXPECT_LENA; EXPECT_EQA;
451 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
452 SetLastError(0xdeadbeef);
453 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
454 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
455 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
457 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
458 SetLastError(0xdeadbeef);
459 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
460 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
461 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
463 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
464 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
465 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
466 EXPECT_LENA;
468 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
469 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
470 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
471 EXPECT_LENA; EXPECT_EQA;
473 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
474 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
475 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
476 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
477 "Expected '', got '%s'\n", buffer );
479 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
480 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
481 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
482 EXPECT_LENA; EXPECT_EQA;
484 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
485 strcpy(Expected, "8:56 AM");
486 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
488 EXPECT_LENA; EXPECT_EQA;
490 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
491 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
494 "Expected '8.@:56AM', got '%s'\n", buffer );
496 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
497 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
498 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
499 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
500 "Expected '', got '%s'\n", buffer );
502 STRINGSA("t/tt", "A/AM"); /* AM time marker */
503 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
504 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
505 EXPECT_LENA; EXPECT_EQA;
507 curtime.wHour = 13;
508 STRINGSA("t/tt", "P/PM"); /* PM time marker */
509 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
510 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
511 EXPECT_LENA; EXPECT_EQA;
513 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
514 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
515 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
516 EXPECT_LENA; EXPECT_EQA;
518 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
519 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
520 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
521 EXPECT_LENA; EXPECT_EQA;
523 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
524 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
526 EXPECT_LENA; EXPECT_EQA;
528 curtime.wHour = 14; /* change this to 14 or 2pm */
529 curtime.wMinute = 5;
530 curtime.wSecond = 3;
531 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 */
532 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
533 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
534 EXPECT_LENA; EXPECT_EQA;
536 curtime.wHour = 0;
537 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
538 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
539 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
540 EXPECT_LENA; EXPECT_EQA;
542 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
543 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
545 EXPECT_LENA; EXPECT_EQA;
547 /* try to convert formatting strings with more than two letters
548 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
549 * NOTE: We expect any letter for which there is an upper case value
550 * we should see a replacement. For letters that DO NOT have
551 * upper case values we should see NO REPLACEMENT.
553 curtime.wHour = 8;
554 curtime.wMinute = 56;
555 curtime.wSecond = 13;
556 curtime.wMilliseconds = 22;
557 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
558 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
559 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
561 EXPECT_LENA; EXPECT_EQA;
563 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
564 strcpy(buffer, "text");
565 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
566 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
567 EXPECT_EQA;
569 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
570 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
571 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
573 EXPECT_LENA; EXPECT_EQA;
575 STRINGSA("'''", "'"); /* invalid quoted string */
576 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
577 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
578 EXPECT_LENA; EXPECT_EQA;
580 /* test that msdn suggested single quotation usage works as expected */
581 STRINGSA("''''", "'"); /* single quote mark */
582 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
583 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
584 EXPECT_LENA; EXPECT_EQA;
586 STRINGSA("''HHHHHH", "08"); /* Normal use */
587 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
588 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
589 EXPECT_LENA; EXPECT_EQA;
591 /* and test for normal use of the single quotation mark */
592 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
593 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
595 EXPECT_LENA; EXPECT_EQA;
597 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
598 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
599 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
600 EXPECT_LENA; EXPECT_EQA;
602 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
603 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
604 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
605 EXPECT_LENA; EXPECT_EQA;
607 curtime.wHour = 25;
608 STRINGSA("'123'tt", ""); /* Invalid time */
609 SetLastError(0xdeadbeef);
610 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
611 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
612 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
614 curtime.wHour = 12;
615 curtime.wMonth = 60; /* Invalid */
616 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
617 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
618 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
619 EXPECT_LENA; EXPECT_EQA;
622 static void test_GetTimeFormatEx(void)
624 int ret;
625 SYSTEMTIME curtime;
626 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
628 if (!pGetTimeFormatEx)
630 win_skip("GetTimeFormatEx not supported\n");
631 return;
634 memset(&curtime, 2, sizeof(SYSTEMTIME));
635 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
636 SetLastError(0xdeadbeef);
637 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
638 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
639 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
641 curtime.wHour = 8;
642 curtime.wMinute = 56;
643 curtime.wSecond = 13;
644 curtime.wMilliseconds = 22;
645 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
646 SetLastError(0xdeadbeef);
647 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
648 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
649 EXPECT_LENW; EXPECT_EQW;
651 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
652 SetLastError(0xdeadbeef);
653 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
654 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
655 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
657 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
658 SetLastError(0xdeadbeef);
659 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
660 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
661 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
663 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
664 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
665 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
666 EXPECT_LENW;
668 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
669 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
670 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
671 EXPECT_LENW; EXPECT_EQW;
673 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
674 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
675 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
676 EXPECT_LENW; EXPECT_EQW;
678 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
679 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
680 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
681 EXPECT_LENW; EXPECT_EQW;
683 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
684 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
685 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
686 EXPECT_LENW; EXPECT_EQW;
688 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
689 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
690 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
691 EXPECT_LENW; EXPECT_EQW;
693 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
694 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
695 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
696 EXPECT_LENW; EXPECT_EQW;
698 STRINGSW("t/tt", "A/AM"); /* AM time marker */
699 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
700 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
701 EXPECT_LENW; EXPECT_EQW;
703 curtime.wHour = 13;
704 STRINGSW("t/tt", "P/PM"); /* PM time marker */
705 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
706 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
707 EXPECT_LENW; EXPECT_EQW;
709 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
710 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
711 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
712 EXPECT_LENW; EXPECT_EQW;
714 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
715 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
716 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
717 EXPECT_LENW; EXPECT_EQW;
719 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
720 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
721 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
722 EXPECT_LENW; EXPECT_EQW;
724 curtime.wHour = 14; /* change this to 14 or 2pm */
725 curtime.wMinute = 5;
726 curtime.wSecond = 3;
727 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 */
728 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
729 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
730 EXPECT_LENW; EXPECT_EQW;
732 curtime.wHour = 0;
733 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
734 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
735 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
736 EXPECT_LENW; EXPECT_EQW;
738 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
739 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
740 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
741 EXPECT_LENW; EXPECT_EQW;
743 /* try to convert formatting strings with more than two letters
744 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
745 * NOTE: We expect any letter for which there is an upper case value
746 * we should see a replacement. For letters that DO NOT have
747 * upper case values we should see NO REPLACEMENT.
749 curtime.wHour = 8;
750 curtime.wMinute = 56;
751 curtime.wSecond = 13;
752 curtime.wMilliseconds = 22;
753 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
754 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
755 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
757 EXPECT_LENW; EXPECT_EQW;
759 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
760 lstrcpyW(buffer, Expected);
761 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
762 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
763 EXPECT_EQW;
765 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
766 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
767 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
768 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
769 EXPECT_LENW; EXPECT_EQW;
771 STRINGSW("'''", "'"); /* invalid quoted string */
772 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
773 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
774 EXPECT_LENW; EXPECT_EQW;
776 /* test that msdn suggested single quotation usage works as expected */
777 STRINGSW("''''", "'"); /* single quote mark */
778 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
779 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
780 EXPECT_LENW; EXPECT_EQW;
782 STRINGSW("''HHHHHH", "08"); /* Normal use */
783 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
784 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
785 EXPECT_LENW; EXPECT_EQW;
787 /* and test for normal use of the single quotation mark */
788 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
789 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
790 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
791 EXPECT_LENW; EXPECT_EQW;
793 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
794 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
795 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
796 EXPECT_LENW; EXPECT_EQW;
798 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
799 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
800 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
801 EXPECT_LENW; EXPECT_EQW;
803 curtime.wHour = 25;
804 STRINGSW("'123'tt", ""); /* Invalid time */
805 SetLastError(0xdeadbeef);
806 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
807 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
808 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
810 curtime.wHour = 12;
811 curtime.wMonth = 60; /* Invalid */
812 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
813 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
814 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
815 EXPECT_LENW; EXPECT_EQW;
818 static void test_GetDateFormatA(void)
820 int ret;
821 SYSTEMTIME curtime;
822 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
823 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
824 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
825 char Broken[BUFFER_SIZE];
826 char short_day[10], month[10], genitive_month[10];
828 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
829 STRINGSA("ddd',' MMM dd yy","");
830 SetLastError(0xdeadbeef);
831 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
832 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
833 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
835 curtime.wYear = 2002;
836 curtime.wMonth = 5;
837 curtime.wDay = 4;
838 curtime.wDayOfWeek = 3;
839 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
840 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
841 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
842 EXPECT_LENA; EXPECT_EQA;
844 /* Same as above but with LOCALE_NOUSEROVERRIDE */
845 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
846 SetLastError(0xdeadbeef);
847 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
848 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
849 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
850 EXPECT_EQA;
852 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
853 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
854 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
855 EXPECT_LENA; EXPECT_EQA;
857 curtime.wHour = 36; /* Invalid */
858 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
859 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
860 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
861 EXPECT_LENA; EXPECT_EQA;
863 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
864 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
865 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
866 EXPECT_EQA;
868 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
869 SetLastError(0xdeadbeef);
870 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
871 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
872 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
874 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
875 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
876 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
877 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
878 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
880 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
881 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
882 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
883 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
884 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
885 "got an unexpected date string '%s'\n", buffer);
887 /* test for expected DATE_YEARMONTH behavior with null format */
888 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
889 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
890 SetLastError(0xdeadbeef);
891 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
892 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
893 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
894 EXPECT_EQA;
896 /* Test that using invalid DATE_* flags results in the correct error */
897 /* and return values */
898 STRINGSA("m/d/y", ""); /* Invalid flags */
899 SetLastError(0xdeadbeef);
900 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
901 &curtime, input, buffer, COUNTOF(buffer));
902 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
903 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
905 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
906 if (!ret)
908 win_skip("LANG_RUSSIAN locale data unavailable\n");
909 return;
912 /* month part should be in genitive form */
913 strcpy(genitive_month, buffer + 2);
914 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
915 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
916 strcpy(month, buffer);
917 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
919 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
920 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
921 strcpy(short_day, buffer);
923 STRINGSA("dd MMMMddd dd", "");
924 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
925 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
926 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
927 EXPECT_EQA;
929 STRINGSA("MMMMddd dd", "");
930 sprintf(Expected, "%s%s 04", month, short_day);
931 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
932 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
933 EXPECT_EQA;
935 STRINGSA("MMMMddd", "");
936 sprintf(Expected, "%s%s", month, short_day);
937 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
938 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
939 EXPECT_EQA;
941 STRINGSA("MMMMdd", "");
942 sprintf(Expected, "%s04", genitive_month);
943 sprintf(Broken, "%s04", month);
944 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
945 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
946 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
947 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
948 "Expected '%s', got '%s'\n", Expected, buffer);
950 STRINGSA("MMMMdd ddd", "");
951 sprintf(Expected, "%s04 %s", genitive_month, short_day);
952 sprintf(Broken, "%s04 %s", month, short_day);
953 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
954 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
955 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
956 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
957 "Expected '%s', got '%s'\n", Expected, buffer);
959 STRINGSA("dd dddMMMM", "");
960 sprintf(Expected, "04 %s%s", short_day, month);
961 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
962 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
963 EXPECT_EQA;
965 STRINGSA("dd dddMMMM ddd MMMMdd", "");
966 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
967 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
968 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
969 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
970 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
971 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
972 "Expected '%s', got '%s'\n", Expected, buffer);
974 /* with literal part */
975 STRINGSA("ddd',' MMMM dd", "");
976 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
977 sprintf(Broken, "%s, %s 04", short_day, month);
978 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
979 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
980 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
981 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
982 "Expected '%s', got '%s'\n", Expected, buffer);
985 static void test_GetDateFormatEx(void)
987 int ret;
988 SYSTEMTIME curtime;
989 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
991 if (!pGetDateFormatEx)
993 win_skip("GetDateFormatEx not supported\n");
994 return;
997 STRINGSW("",""); /* If flags are set, then format must be NULL */
998 SetLastError(0xdeadbeef);
999 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1000 input, buffer, COUNTOF(buffer), NULL);
1001 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1002 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1003 EXPECT_EQW;
1005 STRINGSW("",""); /* NULL buffer, len > 0 */
1006 SetLastError(0xdeadbeef);
1007 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1008 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1009 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1011 STRINGSW("",""); /* NULL buffer, len == 0 */
1012 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1013 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1014 EXPECT_LENW; EXPECT_EQW;
1016 STRINGSW("",""); /* Invalid flag combination */
1017 SetLastError(0xdeadbeef);
1018 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1019 input, NULL, 0, NULL);
1020 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1021 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1022 EXPECT_EQW;
1024 curtime.wYear = 2002;
1025 curtime.wMonth = 10;
1026 curtime.wDay = 23;
1027 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1028 curtime.wHour = 65432; /* Invalid */
1029 curtime.wMinute = 34512; /* Invalid */
1030 curtime.wSecond = 65535; /* Invalid */
1031 curtime.wMilliseconds = 12345;
1032 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1033 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1034 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1035 EXPECT_LENW; EXPECT_EQW;
1037 curtime.wYear = 2002;
1038 curtime.wMonth = 10;
1039 curtime.wDay = 23;
1040 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1041 curtime.wHour = 65432; /* Invalid */
1042 curtime.wMinute = 34512; /* Invalid */
1043 curtime.wSecond = 65535; /* Invalid */
1044 curtime.wMilliseconds = 12345;
1045 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1046 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1047 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1048 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1050 /* Limit tests */
1052 curtime.wYear = 1601;
1053 curtime.wMonth = 1;
1054 curtime.wDay = 1;
1055 curtime.wDayOfWeek = 0; /* Irrelevant */
1056 curtime.wHour = 0;
1057 curtime.wMinute = 0;
1058 curtime.wSecond = 0;
1059 curtime.wMilliseconds = 0;
1060 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1061 SetLastError(0xdeadbeef);
1062 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1063 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064 EXPECT_LENW; EXPECT_EQW;
1066 curtime.wYear = 1600;
1067 curtime.wMonth = 12;
1068 curtime.wDay = 31;
1069 curtime.wDayOfWeek = 0; /* Irrelevant */
1070 curtime.wHour = 23;
1071 curtime.wMinute = 59;
1072 curtime.wSecond = 59;
1073 curtime.wMilliseconds = 999;
1074 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1075 SetLastError(0xdeadbeef);
1076 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1077 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1078 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1081 static void test_GetDateFormatW(void)
1083 int ret;
1084 SYSTEMTIME curtime;
1085 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1086 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1088 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1089 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1090 input, buffer, COUNTOF(buffer));
1091 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1093 win_skip("GetDateFormatW is not implemented\n");
1094 return;
1096 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1097 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1098 EXPECT_EQW;
1100 STRINGSW("",""); /* NULL buffer, len > 0 */
1101 SetLastError(0xdeadbeef);
1102 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1103 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1104 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1106 STRINGSW("",""); /* NULL buffer, len == 0 */
1107 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1108 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1109 EXPECT_LENW; EXPECT_EQW;
1111 curtime.wYear = 2002;
1112 curtime.wMonth = 10;
1113 curtime.wDay = 23;
1114 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1115 curtime.wHour = 65432; /* Invalid */
1116 curtime.wMinute = 34512; /* Invalid */
1117 curtime.wSecond = 65535; /* Invalid */
1118 curtime.wMilliseconds = 12345;
1119 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1120 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1121 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1122 EXPECT_LENW; EXPECT_EQW;
1124 /* Limit tests */
1126 curtime.wYear = 1601;
1127 curtime.wMonth = 1;
1128 curtime.wDay = 1;
1129 curtime.wDayOfWeek = 0; /* Irrelevant */
1130 curtime.wHour = 0;
1131 curtime.wMinute = 0;
1132 curtime.wSecond = 0;
1133 curtime.wMilliseconds = 0;
1134 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1135 SetLastError(0xdeadbeef);
1136 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1137 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1138 EXPECT_LENW; EXPECT_EQW;
1140 curtime.wYear = 1600;
1141 curtime.wMonth = 12;
1142 curtime.wDay = 31;
1143 curtime.wDayOfWeek = 0; /* Irrelevant */
1144 curtime.wHour = 23;
1145 curtime.wMinute = 59;
1146 curtime.wSecond = 59;
1147 curtime.wMilliseconds = 999;
1148 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1149 SetLastError(0xdeadbeef);
1150 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1151 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1152 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1156 #define CY_POS_LEFT 0
1157 #define CY_POS_RIGHT 1
1158 #define CY_POS_LEFT_SPACE 2
1159 #define CY_POS_RIGHT_SPACE 3
1161 static void test_GetCurrencyFormatA(void)
1163 static char szDot[] = { '.', '\0' };
1164 static char szComma[] = { ',', '\0' };
1165 static char szDollar[] = { '$', '\0' };
1166 int ret;
1167 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1168 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1169 CURRENCYFMTA format;
1171 memset(&format, 0, sizeof(format));
1173 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1174 SetLastError(0xdeadbeef);
1175 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1176 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1177 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1179 STRINGSA("23,53",""); /* Invalid character --> Error */
1180 SetLastError(0xdeadbeef);
1181 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1182 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1183 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1185 STRINGSA("--",""); /* Double '-' --> Error */
1186 SetLastError(0xdeadbeef);
1187 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1188 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1189 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1191 STRINGSA("0-",""); /* Trailing '-' --> Error */
1192 SetLastError(0xdeadbeef);
1193 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1194 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1195 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1197 STRINGSA("0..",""); /* Double '.' --> Error */
1198 SetLastError(0xdeadbeef);
1199 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1200 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1201 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1203 STRINGSA(" 0.1",""); /* Leading space --> Error */
1204 SetLastError(0xdeadbeef);
1205 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1206 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1207 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1209 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1210 SetLastError(0xdeadbeef);
1211 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1212 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1213 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1215 STRINGSA("2353",""); /* Format and flags given --> Error */
1216 SetLastError(0xdeadbeef);
1217 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1218 ok( !ret, "Expected ret == 0, got %d\n", ret);
1219 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1220 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1222 STRINGSA("2353",""); /* Invalid format --> Error */
1223 SetLastError(0xdeadbeef);
1224 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1225 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1226 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1228 STRINGSA("2353","$2,353.00"); /* Valid number */
1229 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1230 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1231 EXPECT_LENA; EXPECT_EQA;
1233 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1234 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1235 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1236 EXPECT_LENA; EXPECT_EQA;
1238 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1239 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1240 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1241 EXPECT_LENA; EXPECT_EQA;
1243 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1244 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1245 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1246 EXPECT_LENA; EXPECT_EQA;
1248 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1249 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1250 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1251 EXPECT_LENA; EXPECT_EQA;
1253 format.NumDigits = 0; /* No decimal separator */
1254 format.LeadingZero = 0;
1255 format.Grouping = 0; /* No grouping char */
1256 format.NegativeOrder = 0;
1257 format.PositiveOrder = CY_POS_LEFT;
1258 format.lpDecimalSep = szDot;
1259 format.lpThousandSep = szComma;
1260 format.lpCurrencySymbol = szDollar;
1262 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1263 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1264 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1265 EXPECT_LENA; EXPECT_EQA;
1267 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1268 STRINGSA("2353","$2353.0");
1269 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1270 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1271 EXPECT_LENA; EXPECT_EQA;
1273 format.Grouping = 2; /* Group by 100's */
1274 STRINGSA("2353","$23,53.0");
1275 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1276 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1277 EXPECT_LENA; EXPECT_EQA;
1279 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1280 format.Grouping = 3;
1281 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1282 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1283 EXPECT_LENA; EXPECT_EQA;
1285 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1286 format.NegativeOrder = 2;
1287 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1288 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1289 EXPECT_LENA; EXPECT_EQA;
1291 format.LeadingZero = 1; /* Always provide leading zero */
1292 STRINGSA(".5","$0.5");
1293 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1294 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1295 EXPECT_LENA; EXPECT_EQA;
1297 format.PositiveOrder = CY_POS_RIGHT;
1298 STRINGSA("1","1.0$");
1299 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1300 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1301 EXPECT_LENA; EXPECT_EQA;
1303 format.PositiveOrder = CY_POS_LEFT_SPACE;
1304 STRINGSA("1","$ 1.0");
1305 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1306 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1307 EXPECT_LENA; EXPECT_EQA;
1309 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1310 STRINGSA("1","1.0 $");
1311 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1312 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1313 EXPECT_LENA; EXPECT_EQA;
1315 format.NegativeOrder = 0;
1316 STRINGSA("-1","($1.0)");
1317 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1318 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1319 EXPECT_LENA; EXPECT_EQA;
1321 format.NegativeOrder = 1;
1322 STRINGSA("-1","-$1.0");
1323 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1324 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1325 EXPECT_LENA; EXPECT_EQA;
1327 format.NegativeOrder = 2;
1328 STRINGSA("-1","$-1.0");
1329 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1330 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1331 EXPECT_LENA; EXPECT_EQA;
1333 format.NegativeOrder = 3;
1334 STRINGSA("-1","$1.0-");
1335 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1336 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1337 EXPECT_LENA; EXPECT_EQA;
1339 format.NegativeOrder = 4;
1340 STRINGSA("-1","(1.0$)");
1341 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1342 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1343 EXPECT_LENA; EXPECT_EQA;
1345 format.NegativeOrder = 5;
1346 STRINGSA("-1","-1.0$");
1347 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1348 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1349 EXPECT_LENA; EXPECT_EQA;
1351 format.NegativeOrder = 6;
1352 STRINGSA("-1","1.0-$");
1353 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1354 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1355 EXPECT_LENA; EXPECT_EQA;
1357 format.NegativeOrder = 7;
1358 STRINGSA("-1","1.0$-");
1359 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1360 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1361 EXPECT_LENA; EXPECT_EQA;
1363 format.NegativeOrder = 8;
1364 STRINGSA("-1","-1.0 $");
1365 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1366 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1367 EXPECT_LENA; EXPECT_EQA;
1369 format.NegativeOrder = 9;
1370 STRINGSA("-1","-$ 1.0");
1371 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1372 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1373 EXPECT_LENA; EXPECT_EQA;
1375 format.NegativeOrder = 10;
1376 STRINGSA("-1","1.0 $-");
1377 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1378 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1379 EXPECT_LENA; EXPECT_EQA;
1381 format.NegativeOrder = 11;
1382 STRINGSA("-1","$ 1.0-");
1383 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1384 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1385 EXPECT_LENA; EXPECT_EQA;
1387 format.NegativeOrder = 12;
1388 STRINGSA("-1","$ -1.0");
1389 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1390 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1391 EXPECT_LENA; EXPECT_EQA;
1393 format.NegativeOrder = 13;
1394 STRINGSA("-1","1.0- $");
1395 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1396 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1397 EXPECT_LENA; EXPECT_EQA;
1399 format.NegativeOrder = 14;
1400 STRINGSA("-1","($ 1.0)");
1401 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1402 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1403 EXPECT_LENA; EXPECT_EQA;
1405 format.NegativeOrder = 15;
1406 STRINGSA("-1","(1.0 $)");
1407 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1408 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1409 EXPECT_LENA; EXPECT_EQA;
1412 #define NEG_PARENS 0 /* "(1.1)" */
1413 #define NEG_LEFT 1 /* "-1.1" */
1414 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1415 #define NEG_RIGHT 3 /* "1.1-" */
1416 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1418 static void test_GetNumberFormatA(void)
1420 static char szDot[] = { '.', '\0' };
1421 static char szComma[] = { ',', '\0' };
1422 int ret;
1423 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1424 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1425 NUMBERFMTA format;
1427 memset(&format, 0, sizeof(format));
1429 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1430 SetLastError(0xdeadbeef);
1431 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1432 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1433 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1435 STRINGSA("23,53",""); /* Invalid character --> Error */
1436 SetLastError(0xdeadbeef);
1437 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1438 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1439 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1441 STRINGSA("--",""); /* Double '-' --> Error */
1442 SetLastError(0xdeadbeef);
1443 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1444 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1445 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1447 STRINGSA("0-",""); /* Trailing '-' --> Error */
1448 SetLastError(0xdeadbeef);
1449 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1450 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1451 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1453 STRINGSA("0..",""); /* Double '.' --> Error */
1454 SetLastError(0xdeadbeef);
1455 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1456 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1457 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1459 STRINGSA(" 0.1",""); /* Leading space --> Error */
1460 SetLastError(0xdeadbeef);
1461 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1462 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1463 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1465 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1466 SetLastError(0xdeadbeef);
1467 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1468 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1469 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1471 STRINGSA("2353",""); /* Format and flags given --> Error */
1472 SetLastError(0xdeadbeef);
1473 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1474 ok( !ret, "Expected ret == 0, got %d\n", ret);
1475 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1476 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1478 STRINGSA("2353",""); /* Invalid format --> Error */
1479 SetLastError(0xdeadbeef);
1480 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1481 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1482 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1484 STRINGSA("2353","2,353.00"); /* Valid number */
1485 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1486 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1487 EXPECT_LENA; EXPECT_EQA;
1489 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1490 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1491 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1492 EXPECT_LENA; EXPECT_EQA;
1494 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1495 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1496 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1497 EXPECT_LENA; EXPECT_EQA;
1499 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1500 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1501 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1502 EXPECT_LENA; EXPECT_EQA;
1504 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1505 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1506 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1507 EXPECT_LENA; EXPECT_EQA;
1509 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1510 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1512 EXPECT_LENA; EXPECT_EQA;
1514 format.NumDigits = 0; /* No decimal separator */
1515 format.LeadingZero = 0;
1516 format.Grouping = 0; /* No grouping char */
1517 format.NegativeOrder = 0;
1518 format.lpDecimalSep = szDot;
1519 format.lpThousandSep = szComma;
1521 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1522 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1523 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1524 EXPECT_LENA; EXPECT_EQA;
1526 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1527 STRINGSA("2353","2353.0");
1528 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1529 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1530 EXPECT_LENA; EXPECT_EQA;
1532 format.Grouping = 2; /* Group by 100's */
1533 STRINGSA("2353","23,53.0");
1534 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1535 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1536 EXPECT_LENA; EXPECT_EQA;
1538 STRINGSA("235","235.0"); /* Grouping of a positive number */
1539 format.Grouping = 3;
1540 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1541 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1542 EXPECT_LENA; EXPECT_EQA;
1544 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1545 format.NegativeOrder = NEG_LEFT;
1546 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1547 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1548 EXPECT_LENA; EXPECT_EQA;
1550 format.LeadingZero = 1; /* Always provide leading zero */
1551 STRINGSA(".5","0.5");
1552 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1553 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1554 EXPECT_LENA; EXPECT_EQA;
1556 format.NegativeOrder = NEG_PARENS;
1557 STRINGSA("-1","(1.0)");
1558 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1559 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1560 EXPECT_LENA; EXPECT_EQA;
1562 format.NegativeOrder = NEG_LEFT;
1563 STRINGSA("-1","-1.0");
1564 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1565 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1566 EXPECT_LENA; EXPECT_EQA;
1568 format.NegativeOrder = NEG_LEFT_SPACE;
1569 STRINGSA("-1","- 1.0");
1570 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1571 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1572 EXPECT_LENA; EXPECT_EQA;
1574 format.NegativeOrder = NEG_RIGHT;
1575 STRINGSA("-1","1.0-");
1576 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1577 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1578 EXPECT_LENA; EXPECT_EQA;
1580 format.NegativeOrder = NEG_RIGHT_SPACE;
1581 STRINGSA("-1","1.0 -");
1582 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1583 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1584 EXPECT_LENA; EXPECT_EQA;
1586 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1588 if (IsValidLocale(lcid, 0))
1590 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1591 Expected[3] = 160; /* Non breaking space */
1592 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1593 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1594 EXPECT_LENA; EXPECT_EQA;
1598 static void test_GetNumberFormatEx(void)
1600 int ret;
1601 NUMBERFMTW format;
1602 static WCHAR dotW[] = {'.',0};
1603 static WCHAR commaW[] = {',',0};
1604 static const WCHAR enW[] = {'e','n','-','U','S',0};
1605 static const WCHAR frW[] = {'f','r','-','F','R',0};
1606 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1607 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1609 if (!pGetNumberFormatEx)
1611 win_skip("GetNumberFormatEx is not available.\n");
1612 return;
1615 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1616 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1617 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1618 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1620 STRINGSW("23,53",""); /* Invalid character --> Error */
1621 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1622 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1623 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1625 STRINGSW("--",""); /* Double '-' --> Error */
1626 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1627 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1628 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1630 STRINGSW("0-",""); /* Trailing '-' --> Error */
1631 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1632 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1633 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1635 STRINGSW("0..",""); /* Double '.' --> Error */
1636 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1637 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1638 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1640 STRINGSW(" 0.1",""); /* Leading space --> Error */
1641 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1642 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1643 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1645 STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1646 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1647 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1648 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1650 STRINGSW("23",""); /* Bogus locale --> Error */
1651 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1652 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1653 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1655 memset(&format, 0, sizeof(format));
1657 STRINGSW("2353",""); /* Format and flags given --> Error */
1658 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1659 ok( !ret, "Expected ret == 0, got %d\n", ret);
1660 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1661 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1663 STRINGSW("2353",""); /* Invalid format --> Error */
1664 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1665 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1666 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1668 STRINGSW("2353","2,353.00"); /* Valid number */
1669 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1670 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1671 EXPECT_LENW; EXPECT_EQW;
1673 STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1674 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1675 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1676 EXPECT_LENW; EXPECT_EQW;
1678 STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1679 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1680 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1681 EXPECT_LENW; EXPECT_EQW;
1683 STRINGSW("2353.1","2,353.10"); /* Valid real number */
1684 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1685 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1686 EXPECT_LENW; EXPECT_EQW;
1688 STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1689 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1690 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1691 EXPECT_LENW; EXPECT_EQW;
1693 STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */
1694 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1695 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1696 EXPECT_LENW; EXPECT_EQW;
1698 format.NumDigits = 0; /* No decimal separator */
1699 format.LeadingZero = 0;
1700 format.Grouping = 0; /* No grouping char */
1701 format.NegativeOrder = 0;
1702 format.lpDecimalSep = dotW;
1703 format.lpThousandSep = commaW;
1705 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1706 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1708 EXPECT_LENW; EXPECT_EQW;
1710 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1711 STRINGSW("2353","2353.0");
1712 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1713 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1714 EXPECT_LENW; EXPECT_EQW;
1716 format.Grouping = 2; /* Group by 100's */
1717 STRINGSW("2353","23,53.0");
1718 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1719 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1720 EXPECT_LENW; EXPECT_EQW;
1722 STRINGSW("235","235.0"); /* Grouping of a positive number */
1723 format.Grouping = 3;
1724 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1725 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1726 EXPECT_LENW; EXPECT_EQW;
1728 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1729 format.NegativeOrder = NEG_LEFT;
1730 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1731 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1732 EXPECT_LENW; EXPECT_EQW;
1734 format.LeadingZero = 1; /* Always provide leading zero */
1735 STRINGSW(".5","0.5");
1736 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1737 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1738 EXPECT_LENW; EXPECT_EQW;
1740 format.NegativeOrder = NEG_PARENS;
1741 STRINGSW("-1","(1.0)");
1742 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1743 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1744 EXPECT_LENW; EXPECT_EQW;
1746 format.NegativeOrder = NEG_LEFT;
1747 STRINGSW("-1","-1.0");
1748 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1749 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1750 EXPECT_LENW; EXPECT_EQW;
1752 format.NegativeOrder = NEG_LEFT_SPACE;
1753 STRINGSW("-1","- 1.0");
1754 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1755 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1756 EXPECT_LENW; EXPECT_EQW;
1758 format.NegativeOrder = NEG_RIGHT;
1759 STRINGSW("-1","1.0-");
1760 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1761 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1762 EXPECT_LENW; EXPECT_EQW;
1764 format.NegativeOrder = NEG_RIGHT_SPACE;
1765 STRINGSW("-1","1.0 -");
1766 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1767 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1768 EXPECT_LENW; EXPECT_EQW;
1770 if (pIsValidLocaleName(frW))
1772 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1773 Expected[3] = 160; /* Non breaking space */
1774 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1775 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1776 EXPECT_LENW; EXPECT_EQW;
1780 struct comparestringa_entry {
1781 LCID lcid;
1782 DWORD flags;
1783 const char *first;
1784 int first_len;
1785 const char *second;
1786 int second_len;
1787 int ret;
1790 static const struct comparestringa_entry comparestringa_data[] = {
1791 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1792 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1793 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1794 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1797 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1798 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1799 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1808 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1809 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1810 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1811 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1812 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1813 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1814 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1818 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1820 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1821 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1823 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1824 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1825 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1826 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1827 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1828 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1833 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1834 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1837 static void test_CompareStringA(void)
1839 int ret, i;
1840 char a[256];
1841 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1843 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1845 const struct comparestringa_entry *entry = &comparestringa_data[i];
1847 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1848 entry->second, entry->second_len);
1849 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1852 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1853 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1855 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1856 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1858 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1859 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1861 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1862 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1864 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1866 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1867 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1869 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1870 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1872 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1873 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1875 /* test for CompareStringA flags */
1876 SetLastError(0xdeadbeef);
1877 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1878 ok(GetLastError() == ERROR_INVALID_FLAGS,
1879 "unexpected error code %d\n", GetLastError());
1880 ok(!ret, "CompareStringA must fail with invalid flag\n");
1882 SetLastError(0xdeadbeef);
1883 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1884 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1885 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1886 /* end of test for CompareStringA flags */
1888 ret = lstrcmpA("", "");
1889 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1891 ret = lstrcmpA(NULL, NULL);
1892 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1894 ret = lstrcmpA("", NULL);
1895 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1897 ret = lstrcmpA(NULL, "");
1898 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1901 if (0) { /* this requires collation table patch to make it MS compatible */
1902 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1903 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1905 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1906 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1908 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1909 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1911 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1912 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1914 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1915 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1917 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1918 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1920 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1921 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1923 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1924 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1926 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1927 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1929 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1930 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1932 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1933 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1935 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1936 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1940 /* WinXP handles embedded NULLs differently than earlier versions */
1941 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1942 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1944 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1945 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);
1947 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1948 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1950 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1951 ok(ret == CSTR_EQUAL || /* win2k */
1952 ret == CSTR_GREATER_THAN,
1953 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1955 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1956 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1958 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1959 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1961 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1962 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1964 ret = lstrcmpiA("#", ".");
1965 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1967 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1969 /* \xB9 character lies between a and b */
1970 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1971 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1972 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1973 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1975 memset(a, 'a', sizeof(a));
1976 SetLastError(0xdeadbeef);
1977 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1978 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1979 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1982 static void test_CompareStringW(void)
1984 WCHAR *str1, *str2;
1985 SYSTEM_INFO si;
1986 DWORD old_prot;
1987 BOOL success;
1988 char *buf;
1989 int ret;
1991 GetSystemInfo(&si);
1992 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1993 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1994 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1995 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1996 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1997 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1999 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2000 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2001 *str1 = 'A';
2002 *str2 = 'B';
2004 /* CompareStringW should abort on the first non-matching character */
2005 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2006 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2008 success = VirtualFree(buf, 0, MEM_RELEASE);
2009 ok(success, "VirtualFree failed with %u\n", GetLastError());
2012 struct comparestringex_test {
2013 const char *locale;
2014 DWORD flags;
2015 const WCHAR first[2];
2016 const WCHAR second[2];
2017 INT ret;
2018 INT broken;
2019 BOOL todo;
2022 static const struct comparestringex_test comparestringex_tests[] = {
2023 /* default behavior */
2024 { /* 0 */
2025 "tr-TR", 0,
2026 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2028 { /* 1 */
2029 "tr-TR", 0,
2030 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2032 { /* 2 */
2033 "tr-TR", 0,
2034 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2036 { /* 3 */
2037 "tr-TR", 0,
2038 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2040 { /* 4 */
2041 "tr-TR", 0,
2042 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2044 { /* 5 */
2045 "tr-TR", 0,
2046 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2048 /* with NORM_IGNORECASE */
2049 { /* 6 */
2050 "tr-TR", NORM_IGNORECASE,
2051 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2053 { /* 7 */
2054 "tr-TR", NORM_IGNORECASE,
2055 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2057 { /* 8 */
2058 "tr-TR", NORM_IGNORECASE,
2059 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2061 { /* 9 */
2062 "tr-TR", NORM_IGNORECASE,
2063 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2065 { /* 10 */
2066 "tr-TR", NORM_IGNORECASE,
2067 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2069 { /* 11 */
2070 "tr-TR", NORM_IGNORECASE,
2071 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2073 /* with NORM_LINGUISTIC_CASING */
2074 { /* 12 */
2075 "tr-TR", NORM_LINGUISTIC_CASING,
2076 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2078 { /* 13 */
2079 "tr-TR", NORM_LINGUISTIC_CASING,
2080 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2082 { /* 14 */
2083 "tr-TR", NORM_LINGUISTIC_CASING,
2084 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2086 { /* 15 */
2087 "tr-TR", NORM_LINGUISTIC_CASING,
2088 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2090 { /* 16 */
2091 "tr-TR", NORM_LINGUISTIC_CASING,
2092 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2094 { /* 17 */
2095 "tr-TR", NORM_LINGUISTIC_CASING,
2096 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2098 /* with LINGUISTIC_IGNORECASE */
2099 { /* 18 */
2100 "tr-TR", LINGUISTIC_IGNORECASE,
2101 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2103 { /* 19 */
2104 "tr-TR", LINGUISTIC_IGNORECASE,
2105 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2107 { /* 20 */
2108 "tr-TR", LINGUISTIC_IGNORECASE,
2109 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2111 { /* 21 */
2112 "tr-TR", LINGUISTIC_IGNORECASE,
2113 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2115 { /* 22 */
2116 "tr-TR", LINGUISTIC_IGNORECASE,
2117 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2119 { /* 23 */
2120 "tr-TR", LINGUISTIC_IGNORECASE,
2121 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2123 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2124 { /* 24 */
2125 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2126 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2128 { /* 25 */
2129 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2130 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2132 { /* 26 */
2133 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2134 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2136 { /* 27 */
2137 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2138 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2140 { /* 28 */
2141 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2142 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2144 { /* 29 */
2145 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2146 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2148 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2149 { /* 30 */
2150 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2151 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2153 { /* 31 */
2154 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2155 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2157 { /* 32 */
2158 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2159 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2161 { /* 33 */
2162 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2163 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2165 { /* 34 */
2166 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2167 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2169 { /* 35 */
2170 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2171 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2175 static void test_CompareStringEx(void)
2177 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2178 WCHAR locale[6];
2179 INT ret, i;
2181 /* CompareStringEx is only available on Vista+ */
2182 if (!pCompareStringEx)
2184 win_skip("CompareStringEx not supported\n");
2185 return;
2188 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2190 const struct comparestringex_test *e = &comparestringex_tests[i];
2192 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2193 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2194 todo_wine_if (e->todo)
2195 ok(ret == e->ret || broken(ret == e->broken),
2196 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2201 static const DWORD lcmap_invalid_flags[] = {
2203 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2204 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2205 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2206 LCMAP_LOWERCASE | SORT_STRINGSORT,
2207 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2208 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2209 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2210 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2211 LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2212 LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2213 LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2214 LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2215 LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2216 LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2217 LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2218 LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2219 LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2220 LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2221 LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2222 LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2223 LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2224 LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2225 LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2226 LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2229 static void test_LCMapStringA(void)
2231 int ret, ret2, i;
2232 char buf[256], buf2[256];
2233 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2234 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2235 static const char symbols_stripped[] = "justateststring1";
2237 SetLastError(0xdeadbeef);
2238 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2239 lower_case, -1, buf, sizeof(buf));
2240 ok(ret == lstrlenA(lower_case) + 1,
2241 "ret %d, error %d, expected value %d\n",
2242 ret, GetLastError(), lstrlenA(lower_case) + 1);
2243 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2245 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2246 upper_case, -1, buf, sizeof(buf));
2247 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2248 ok(GetLastError() == ERROR_INVALID_FLAGS,
2249 "unexpected error code %d\n", GetLastError());
2251 /* test invalid flag combinations */
2252 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2253 lstrcpyA(buf, "foo");
2254 SetLastError(0xdeadbeef);
2255 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2256 lower_case, -1, buf, sizeof(buf));
2257 ok(GetLastError() == ERROR_INVALID_FLAGS,
2258 "LCMapStringA (flag %08x) unexpected error code %d\n",
2259 lcmap_invalid_flags[i], GetLastError());
2260 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2261 lcmap_invalid_flags[i], ret);
2264 /* test LCMAP_LOWERCASE */
2265 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2266 upper_case, -1, buf, sizeof(buf));
2267 ok(ret == lstrlenA(upper_case) + 1,
2268 "ret %d, error %d, expected value %d\n",
2269 ret, GetLastError(), lstrlenA(upper_case) + 1);
2270 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2272 /* test LCMAP_UPPERCASE */
2273 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2274 lower_case, -1, buf, sizeof(buf));
2275 ok(ret == lstrlenA(lower_case) + 1,
2276 "ret %d, error %d, expected value %d\n",
2277 ret, GetLastError(), lstrlenA(lower_case) + 1);
2278 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2280 /* test buffer overflow */
2281 SetLastError(0xdeadbeef);
2282 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2283 lower_case, -1, buf, 4);
2284 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2285 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2287 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2288 lstrcpyA(buf, lower_case);
2289 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2290 buf, -1, buf, sizeof(buf));
2291 if (!ret) /* Win9x */
2292 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2293 else
2295 ok(ret == lstrlenA(lower_case) + 1,
2296 "ret %d, error %d, expected value %d\n",
2297 ret, GetLastError(), lstrlenA(lower_case) + 1);
2298 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2300 lstrcpyA(buf, upper_case);
2301 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2302 buf, -1, buf, sizeof(buf));
2303 if (!ret) /* Win9x */
2304 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2305 else
2307 ok(ret == lstrlenA(upper_case) + 1,
2308 "ret %d, error %d, expected value %d\n",
2309 ret, GetLastError(), lstrlenA(lower_case) + 1);
2310 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2313 /* otherwise src == dst should fail */
2314 SetLastError(0xdeadbeef);
2315 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2316 buf, 10, buf, sizeof(buf));
2317 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2318 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2319 "unexpected error code %d\n", GetLastError());
2320 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2322 /* test whether '\0' is always appended */
2323 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2324 upper_case, -1, buf, sizeof(buf));
2325 ok(ret, "LCMapStringA must succeed\n");
2326 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2327 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2328 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2329 ok(ret2, "LCMapStringA must succeed\n");
2330 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2331 ok(ret == ret2, "lengths of sort keys must be equal\n");
2332 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2334 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2335 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2336 upper_case, -1, buf, sizeof(buf));
2337 ok(ret, "LCMapStringA must succeed\n");
2338 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2339 lower_case, -1, buf2, sizeof(buf2));
2340 ok(ret2, "LCMapStringA must succeed\n");
2341 ok(ret == ret2, "lengths of sort keys must be equal\n");
2342 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2344 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2345 results from plain LCMAP_SORTKEY on Vista */
2347 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2348 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2349 lower_case, -1, buf, sizeof(buf));
2350 ok(ret, "LCMapStringA must succeed\n");
2351 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2352 symbols_stripped, -1, buf2, sizeof(buf2));
2353 ok(ret2, "LCMapStringA must succeed\n");
2354 ok(ret == ret2, "lengths of sort keys must be equal\n");
2355 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2357 /* test NORM_IGNORENONSPACE */
2358 lstrcpyA(buf, "foo");
2359 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2360 lower_case, -1, buf, sizeof(buf));
2361 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2362 lstrlenA(lower_case) + 1, ret);
2363 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2365 /* test NORM_IGNORESYMBOLS */
2366 lstrcpyA(buf, "foo");
2367 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2368 lower_case, -1, buf, sizeof(buf));
2369 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2370 lstrlenA(symbols_stripped) + 1, ret);
2371 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2373 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2374 lstrcpyA(buf, "foo");
2375 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2376 lower_case, -1, buf, sizeof(buf));
2377 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2378 lstrlenA(symbols_stripped) + 1, ret);
2379 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2381 /* test srclen = 0 */
2382 SetLastError(0xdeadbeef);
2383 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2384 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2385 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2386 "unexpected error code %d\n", GetLastError());
2389 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2391 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2393 const static WCHAR japanese_text[] = {
2394 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2395 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2397 const static WCHAR hiragana_text[] = {
2398 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2399 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2401 const static WCHAR katakana_text[] = {
2402 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2403 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2405 const static WCHAR halfwidth_text[] = {
2406 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2407 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2409 int ret, ret2, i;
2410 WCHAR buf[256], buf2[256];
2411 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2413 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2414 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2415 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2416 todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2417 "%s ret %d, error %d, expected value %d\n", func_name,
2418 ret, GetLastError(), lstrlenW(title_case) + 1);
2419 todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2420 "Expected title case string\n");
2422 /* test invalid flag combinations */
2423 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2424 lstrcpyW(buf, fooW);
2425 SetLastError(0xdeadbeef);
2426 ret = func_ptr(lcmap_invalid_flags[i],
2427 lower_case, -1, buf, sizeof(buf));
2428 ok(GetLastError() == ERROR_INVALID_FLAGS,
2429 "%s (flag %08x) unexpected error code %d\n",
2430 func_name, lcmap_invalid_flags[i], GetLastError());
2431 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2432 func_name, lcmap_invalid_flags[i], ret);
2435 /* test LCMAP_LOWERCASE */
2436 ret = func_ptr(LCMAP_LOWERCASE,
2437 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2438 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2439 ret, GetLastError(), lstrlenW(upper_case) + 1);
2440 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2442 /* test LCMAP_UPPERCASE */
2443 ret = func_ptr(LCMAP_UPPERCASE,
2444 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2445 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2446 ret, GetLastError(), lstrlenW(lower_case) + 1);
2447 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2449 /* test LCMAP_HIRAGANA */
2450 ret = func_ptr(LCMAP_HIRAGANA,
2451 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2452 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2453 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2454 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2456 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2457 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2458 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2459 ret, GetLastError());
2460 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2461 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2462 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2464 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2465 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
2466 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2467 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2468 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2469 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2471 /* test LCMAP_FULLWIDTH */
2472 ret = func_ptr(LCMAP_FULLWIDTH,
2473 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2474 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2475 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2476 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2478 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2479 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2481 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2482 (half-width katakana is converted into full-wdith hiragana) */
2483 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
2484 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2485 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2486 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2487 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2489 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2490 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2492 /* test LCMAP_HALFWIDTH */
2493 ret = func_ptr(LCMAP_HALFWIDTH,
2494 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2495 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2496 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2497 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2499 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2500 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2502 /* test buffer overflow */
2503 SetLastError(0xdeadbeef);
2504 ret = func_ptr(LCMAP_UPPERCASE,
2505 lower_case, -1, buf, 4);
2506 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2507 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2509 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2510 Thus, it requires two WCHARs. */
2511 buf[0] = 0x30ac;
2512 SetLastError(0xdeadbeef);
2513 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2514 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2515 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2517 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2518 lstrcpyW(buf, lower_case);
2519 ret = func_ptr(LCMAP_UPPERCASE,
2520 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2521 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2522 ret, GetLastError(), lstrlenW(lower_case) + 1);
2523 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2525 lstrcpyW(buf, upper_case);
2526 ret = func_ptr(LCMAP_LOWERCASE,
2527 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2528 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2529 ret, GetLastError(), lstrlenW(lower_case) + 1);
2530 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2532 /* otherwise src == dst should fail */
2533 SetLastError(0xdeadbeef);
2534 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2535 buf, 10, buf, sizeof(buf));
2536 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2537 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2538 "%s unexpected error code %d\n", func_name, GetLastError());
2539 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2541 /* test whether '\0' is always appended */
2542 ret = func_ptr(LCMAP_SORTKEY,
2543 upper_case, -1, buf, sizeof(buf));
2544 ok(ret, "%s func_ptr must succeed\n", func_name);
2545 ret2 = func_ptr(LCMAP_SORTKEY,
2546 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2547 ok(ret, "%s func_ptr must succeed\n", func_name);
2548 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2549 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2551 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2552 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2553 upper_case, -1, buf, sizeof(buf));
2554 ok(ret, "%s func_ptr must succeed\n", func_name);
2555 ret2 = func_ptr(LCMAP_SORTKEY,
2556 lower_case, -1, buf2, sizeof(buf2));
2557 ok(ret2, "%s func_ptr must succeed\n", func_name);
2558 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2559 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2561 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2562 results from plain LCMAP_SORTKEY on Vista */
2564 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2565 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2566 lower_case, -1, buf, sizeof(buf));
2567 ok(ret, "%s func_ptr must succeed\n", func_name);
2568 ret2 = func_ptr(LCMAP_SORTKEY,
2569 symbols_stripped, -1, buf2, sizeof(buf2));
2570 ok(ret2, "%s func_ptr must succeed\n", func_name);
2571 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2572 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2574 /* test NORM_IGNORENONSPACE */
2575 lstrcpyW(buf, fooW);
2576 ret = func_ptr(NORM_IGNORENONSPACE,
2577 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2578 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2579 lstrlenW(lower_case) + 1, ret);
2580 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2582 /* test NORM_IGNORESYMBOLS */
2583 lstrcpyW(buf, fooW);
2584 ret = func_ptr(NORM_IGNORESYMBOLS,
2585 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2586 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2587 lstrlenW(symbols_stripped) + 1, ret);
2588 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2590 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2591 lstrcpyW(buf, fooW);
2592 ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2593 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2594 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2595 lstrlenW(symbols_stripped) + 1, ret);
2596 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2598 /* test srclen = 0 */
2599 SetLastError(0xdeadbeef);
2600 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2601 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2602 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2603 "%s unexpected error code %d\n", func_name, GetLastError());
2606 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2608 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2611 static void test_LCMapStringW(void)
2613 int ret;
2614 WCHAR buf[256];
2616 trace("testing LCMapStringW\n");
2618 SetLastError(0xdeadbeef);
2619 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2620 todo_wine {
2621 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2622 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2625 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2628 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2630 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2633 static void test_LCMapStringEx(void)
2635 int ret;
2636 WCHAR buf[256];
2638 if (!pLCMapStringEx)
2640 win_skip( "LCMapStringEx not available\n" );
2641 return;
2644 trace("testing LCMapStringEx\n");
2646 SetLastError(0xdeadbeef);
2647 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2648 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2649 todo_wine {
2650 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2651 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2654 /* test reserved parameters */
2655 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2656 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2657 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2658 ret, GetLastError(), lstrlenW(upper_case) + 1);
2659 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2661 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2662 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2663 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2664 ret, GetLastError(), lstrlenW(upper_case) + 1);
2665 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2667 /* crashes on native */
2668 if(0)
2669 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2670 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2672 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2675 struct neutralsublang_name_t {
2676 WCHAR name[3];
2677 LCID lcid;
2678 int todo;
2681 static const struct neutralsublang_name_t neutralsublang_names[] = {
2682 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2683 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2684 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2685 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2686 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2687 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2688 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2689 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2690 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2691 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2692 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2693 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2694 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2695 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2696 { {0} }
2699 static void test_LocaleNameToLCID(void)
2701 LCID lcid;
2702 INT ret;
2703 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2704 static const WCHAR enW[] = {'e','n',0};
2706 if (!pLocaleNameToLCID)
2708 win_skip( "LocaleNameToLCID not available\n" );
2709 return;
2712 /* special cases */
2713 buffer[0] = 0;
2714 SetLastError(0xdeadbeef);
2715 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2716 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2717 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2718 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2719 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2720 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2722 buffer[0] = 0;
2723 SetLastError(0xdeadbeef);
2724 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2725 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2726 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2727 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2728 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2729 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2731 buffer[0] = 0;
2732 SetLastError(0xdeadbeef);
2733 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2734 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2735 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2736 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2737 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2739 /* bad name */
2740 SetLastError(0xdeadbeef);
2741 lcid = pLocaleNameToLCID(fooW, 0);
2742 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2743 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2745 /* english neutral name */
2746 lcid = pLocaleNameToLCID(enW, 0);
2747 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2748 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2749 if (lcid)
2751 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2753 while (*ptr->name)
2755 lcid = pLocaleNameToLCID(ptr->name, 0);
2756 todo_wine_if (ptr->todo)
2757 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2758 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2760 *buffer = 0;
2761 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2762 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2763 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2764 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2766 ptr++;
2771 /* this requires collation table patch to make it MS compatible */
2772 static const char * const strings_sorted[] =
2774 "'",
2775 "-",
2776 "!",
2777 "\"",
2778 ".",
2779 ":",
2780 "\\",
2781 "_",
2782 "`",
2783 "{",
2784 "}",
2785 "+",
2786 "0",
2787 "1",
2788 "2",
2789 "3",
2790 "4",
2791 "5",
2792 "6",
2793 "7",
2794 "8",
2795 "9",
2796 "a",
2797 "A",
2798 "b",
2799 "B",
2800 "c",
2804 static const char * const strings[] =
2806 "C",
2807 "\"",
2808 "9",
2809 "'",
2810 "}",
2811 "-",
2812 "7",
2813 "+",
2814 "`",
2815 "1",
2816 "a",
2817 "5",
2818 "\\",
2819 "8",
2820 "B",
2821 "3",
2822 "_",
2823 "6",
2824 "{",
2825 "2",
2826 "c",
2827 "4",
2828 "!",
2829 "0",
2830 "A",
2831 ":",
2832 "b",
2836 static int compare_string1(const void *e1, const void *e2)
2838 const char *s1 = *(const char *const *)e1;
2839 const char *s2 = *(const char *const *)e2;
2841 return lstrcmpA(s1, s2);
2844 static int compare_string2(const void *e1, const void *e2)
2846 const char *s1 = *(const char *const *)e1;
2847 const char *s2 = *(const char *const *)e2;
2849 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2852 static int compare_string3(const void *e1, const void *e2)
2854 const char *s1 = *(const char *const *)e1;
2855 const char *s2 = *(const char *const *)e2;
2856 char key1[256], key2[256];
2858 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2859 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2860 return strcmp(key1, key2);
2863 static void test_sorting(void)
2865 char buf[256];
2866 char **str_buf = (char **)buf;
2867 int i;
2869 assert(sizeof(buf) >= sizeof(strings));
2871 /* 1. sort using lstrcmpA */
2872 memcpy(buf, strings, sizeof(strings));
2873 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2874 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2876 ok(!strcmp(strings_sorted[i], str_buf[i]),
2877 "qsort using lstrcmpA failed for element %d\n", i);
2879 /* 2. sort using CompareStringA */
2880 memcpy(buf, strings, sizeof(strings));
2881 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2882 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2884 ok(!strcmp(strings_sorted[i], str_buf[i]),
2885 "qsort using CompareStringA failed for element %d\n", i);
2887 /* 3. sort using sort keys */
2888 memcpy(buf, strings, sizeof(strings));
2889 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2890 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2892 ok(!strcmp(strings_sorted[i], str_buf[i]),
2893 "qsort using sort keys failed for element %d\n", i);
2897 static void test_FoldStringA(void)
2899 int ret, i, j;
2900 BOOL is_special;
2901 char src[256], dst[256];
2902 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2903 static const char digits_dst[] = { '1','2','3','\0' };
2904 static const char composite_src[] =
2906 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2907 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2908 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2909 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2910 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2911 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2912 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2913 0xfb,0xfc,0xfd,0xff,'\0'
2915 static const char composite_dst[] =
2917 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2918 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2919 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2920 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2921 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2922 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2923 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2924 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2925 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2926 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2927 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2928 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2929 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2930 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2931 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2933 static const char composite_dst_alt[] =
2935 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2936 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2937 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2938 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2939 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2940 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2941 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2942 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2943 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2944 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2945 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2946 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2947 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2948 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2949 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2951 static const char ligatures_src[] =
2953 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2955 static const char ligatures_dst[] =
2957 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2959 static const struct special
2961 char src;
2962 char dst[4];
2963 } foldczone_special[] =
2965 /* src dst */
2966 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2967 { 0x98, { 0x20, 0x7e, 0x00 } },
2968 { 0x99, { 0x54, 0x4d, 0x00 } },
2969 { 0xa0, { 0x20, 0x00 } },
2970 { 0xa8, { 0x20, 0xa8, 0x00 } },
2971 { 0xaa, { 0x61, 0x00 } },
2972 { 0xaf, { 0x20, 0xaf, 0x00 } },
2973 { 0xb2, { 0x32, 0x00 } },
2974 { 0xb3, { 0x33, 0x00 } },
2975 { 0xb4, { 0x20, 0xb4, 0x00 } },
2976 { 0xb8, { 0x20, 0xb8, 0x00 } },
2977 { 0xb9, { 0x31, 0x00 } },
2978 { 0xba, { 0x6f, 0x00 } },
2979 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2980 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2981 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2982 { 0x00 }
2985 if (!pFoldStringA)
2986 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2988 /* these tests are locale specific */
2989 if (GetACP() != 1252)
2991 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2992 return;
2995 /* MAP_FOLDDIGITS */
2996 SetLastError(0);
2997 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2998 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3000 win_skip("FoldStringA is not implemented\n");
3001 return;
3003 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
3004 ok(strcmp(dst, digits_dst) == 0,
3005 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
3006 for (i = 1; i < 256; i++)
3008 if (!strchr(digits_src, i))
3010 src[0] = i;
3011 src[1] = '\0';
3012 SetLastError(0);
3013 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
3014 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3015 ok(dst[0] == src[0],
3016 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3020 /* MAP_EXPAND_LIGATURES */
3021 SetLastError(0);
3022 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3023 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3024 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3025 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3026 ok(strcmp(dst, ligatures_dst) == 0,
3027 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3028 for (i = 1; i < 256; i++)
3030 if (!strchr(ligatures_src, i))
3032 src[0] = i;
3033 src[1] = '\0';
3034 SetLastError(0);
3035 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3036 if (ret == 3)
3038 /* Vista */
3039 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3040 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3041 "Got %s for %d\n", dst, i);
3043 else
3045 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3046 ok(dst[0] == src[0],
3047 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3053 /* MAP_COMPOSITE */
3054 SetLastError(0);
3055 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3056 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3057 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3058 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3059 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3061 for (i = 1; i < 256; i++)
3063 if (!strchr(composite_src, i))
3065 src[0] = i;
3066 src[1] = '\0';
3067 SetLastError(0);
3068 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3069 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3070 ok(dst[0] == src[0],
3071 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3072 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3076 /* MAP_FOLDCZONE */
3077 for (i = 1; i < 256; i++)
3079 src[0] = i;
3080 src[1] = '\0';
3081 SetLastError(0);
3082 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3083 is_special = FALSE;
3084 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3086 if (foldczone_special[j].src == src[0])
3088 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3089 "Expected ret == 2 or %d, got %d, error %d\n",
3090 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3091 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3092 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3093 (unsigned char)src[0]);
3094 is_special = TRUE;
3097 if (! is_special)
3099 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3100 ok(src[0] == dst[0],
3101 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3102 (unsigned char)src[0], (unsigned char)dst[0]);
3106 /* MAP_PRECOMPOSED */
3107 for (i = 1; i < 256; i++)
3109 src[0] = i;
3110 src[1] = '\0';
3111 SetLastError(0);
3112 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3113 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3114 ok(src[0] == dst[0],
3115 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3116 (unsigned char)src[0], (unsigned char)dst[0]);
3120 static void test_FoldStringW(void)
3122 int ret;
3123 unsigned int i, j;
3124 WCHAR src[256], dst[256], ch, prev_ch = 1;
3125 static const DWORD badFlags[] =
3128 MAP_PRECOMPOSED|MAP_COMPOSITE,
3129 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3130 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3132 /* Ranges of digits 0-9 : Must be sorted! */
3133 static const WCHAR digitRanges[] =
3135 0x0030, /* '0'-'9' */
3136 0x0660, /* Eastern Arabic */
3137 0x06F0, /* Arabic - Hindu */
3138 0x07C0, /* Nko */
3139 0x0966, /* Devengari */
3140 0x09E6, /* Bengalii */
3141 0x0A66, /* Gurmukhi */
3142 0x0AE6, /* Gujarati */
3143 0x0B66, /* Oriya */
3144 0x0BE6, /* Tamil - No 0 */
3145 0x0C66, /* Telugu */
3146 0x0CE6, /* Kannada */
3147 0x0D66, /* Maylayalam */
3148 0x0DE6, /* Sinhala Lith */
3149 0x0E50, /* Thai */
3150 0x0ED0, /* Laos */
3151 0x0F20, /* Tibet */
3152 0x0F29, /* Tibet half - 0 is out of sequence */
3153 0x1040, /* Myanmar */
3154 0x1090, /* Myanmar Shan */
3155 0x1368, /* Ethiopic - no 0 */
3156 0x17E0, /* Khmer */
3157 0x1810, /* Mongolian */
3158 0x1946, /* Limbu */
3159 0x19D0, /* New Tai Lue */
3160 0x1A80, /* Tai Tham Hora */
3161 0x1A90, /* Tai Tham Tham */
3162 0x1B50, /* Balinese */
3163 0x1BB0, /* Sundanese */
3164 0x1C40, /* Lepcha */
3165 0x1C50, /* Ol Chiki */
3166 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3167 0x2080, /* Subscript */
3168 0x245F, /* Circled - 0 is out of sequence */
3169 0x2473, /* Bracketed */
3170 0x2487, /* Full stop */
3171 0x24F4, /* Double Circled */
3172 0x2775, /* Inverted circled - No 0 */
3173 0x277F, /* Patterned circled - No 0 */
3174 0x2789, /* Inverted Patterned circled - No 0 */
3175 0x3020, /* Hangzhou */
3176 0xA620, /* Vai */
3177 0xA8D0, /* Saurashtra */
3178 0xA900, /* Kayah Li */
3179 0xA9D0, /* Javanese */
3180 0xA9F0, /* Myanmar Tai Laing */
3181 0xAA50, /* Cham */
3182 0xABF0, /* Meetei Mayek */
3183 0xff10, /* Pliene chasse (?) */
3184 0xffff /* Terminator */
3186 /* Digits which are represented, but out of sequence */
3187 static const WCHAR outOfSequenceDigits[] =
3189 0xB9, /* Superscript 1 */
3190 0xB2, /* Superscript 2 */
3191 0xB3, /* Superscript 3 */
3192 0x0C78, /* Telugu Fraction 0 */
3193 0x0C79, /* Telugu Fraction 1 */
3194 0x0C7A, /* Telugu Fraction 2 */
3195 0x0C7B, /* Telugu Fraction 3 */
3196 0x0C7C, /* Telugu Fraction 1 */
3197 0x0C7D, /* Telugu Fraction 2 */
3198 0x0C7E, /* Telugu Fraction 3 */
3199 0x0F33, /* Tibetan half zero */
3200 0x19DA, /* New Tai Lue Tham 1 */
3201 0x24EA, /* Circled 0 */
3202 0x24FF, /* Negative Circled 0 */
3203 0x3007, /* Ideographic number zero */
3204 '\0' /* Terminator */
3206 /* Digits in digitRanges for which no representation is available */
3207 static const WCHAR noDigitAvailable[] =
3209 0x0BE6, /* No Tamil 0 */
3210 0x0F29, /* No Tibetan half zero (out of sequence) */
3211 0x1368, /* No Ethiopic 0 */
3212 0x2473, /* No Bracketed 0 */
3213 0x2487, /* No 0 Full stop */
3214 0x24F4, /* No double circled 0 */
3215 0x2775, /* No inverted circled 0 */
3216 0x277F, /* No patterned circled */
3217 0x2789, /* No inverted Patterned circled */
3218 0x3020, /* No Hangzhou 0 */
3219 '\0' /* Terminator */
3221 static const WCHAR foldczone_src[] =
3223 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
3224 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3226 static const WCHAR foldczone_dst[] =
3228 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3230 static const WCHAR foldczone_todo_src[] =
3232 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3234 static const WCHAR foldczone_todo_dst[] =
3236 0x3cb,0x1f0,' ','a',0
3238 static const WCHAR foldczone_todo_broken_dst[] =
3240 0x3cb,0x1f0,0xa0,0xaa,0
3242 static const WCHAR ligatures_src[] =
3244 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
3245 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3246 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3247 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3248 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3249 0xfb04, 0xfb05, 0xfb06, '\0'
3251 static const WCHAR ligatures_dst[] =
3253 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3254 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3255 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3256 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3257 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3258 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3261 if (!pFoldStringW)
3263 win_skip("FoldStringW is not available\n");
3264 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3267 /* Invalid flag combinations */
3268 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3270 src[0] = dst[0] = '\0';
3271 SetLastError(0);
3272 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3273 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3275 win_skip("FoldStringW is not implemented\n");
3276 return;
3278 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3279 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3282 /* src & dst cannot be the same */
3283 SetLastError(0);
3284 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3285 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3286 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3288 /* src can't be NULL */
3289 SetLastError(0);
3290 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3291 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3292 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3294 /* srclen can't be 0 */
3295 SetLastError(0);
3296 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3297 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3298 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3300 /* dstlen can't be < 0 */
3301 SetLastError(0);
3302 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3303 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3304 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3306 /* Ret includes terminating NUL which is appended if srclen = -1 */
3307 SetLastError(0);
3308 src[0] = 'A';
3309 src[1] = '\0';
3310 dst[0] = '\0';
3311 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3312 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3313 ok(dst[0] == 'A' && dst[1] == '\0',
3314 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3315 'A', '\0', ret, dst[0], dst[1], GetLastError());
3317 /* If size is given, result is not NUL terminated */
3318 SetLastError(0);
3319 src[0] = 'A';
3320 src[1] = 'A';
3321 dst[0] = 'X';
3322 dst[1] = 'X';
3323 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3324 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3325 ok(dst[0] == 'A' && dst[1] == 'X',
3326 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3327 'A','X', ret, dst[0], dst[1], GetLastError());
3329 /* MAP_FOLDDIGITS */
3330 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3332 /* Check everything before this range */
3333 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3335 SetLastError(0);
3336 src[0] = ch;
3337 src[1] = dst[0] = '\0';
3338 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3339 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3341 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3342 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3343 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3344 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3345 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3346 "char %04x should not be a digit\n", ch );
3349 if (digitRanges[j] == 0xffff)
3350 break; /* Finished the whole code point space */
3352 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3354 WCHAR c;
3356 /* Map out of sequence characters */
3357 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3358 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3359 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3360 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3361 else c = ch;
3362 SetLastError(0);
3363 src[0] = c;
3364 src[1] = dst[0] = '\0';
3365 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3366 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3368 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3369 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3370 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3371 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3372 strchrW(noDigitAvailable, c),
3373 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3374 ch, '0' + digitRanges[j] - ch, dst[0]);
3376 prev_ch = ch;
3379 /* MAP_FOLDCZONE */
3380 SetLastError(0);
3381 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3382 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3383 "Got %d, error %d\n", ret, GetLastError());
3384 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3385 "MAP_FOLDCZONE: Expanded incorrectly\n");
3387 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3388 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3389 "Got %d, error %d\n", ret, GetLastError());
3390 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3391 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3392 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3394 /* MAP_EXPAND_LIGATURES */
3395 SetLastError(0);
3396 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3397 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3398 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3399 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3400 "Got %d, error %d\n", ret, GetLastError());
3401 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3402 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3405 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3410 #define LCID_OK(l) \
3411 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3412 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3413 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3414 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3415 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3417 static void test_ConvertDefaultLocale(void)
3419 LCID lcid;
3421 /* Doesn't change lcid, even if non default sublang/sort used */
3422 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3423 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3424 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3425 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3427 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3428 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3429 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3430 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3431 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3433 /* Invariant language is not treated specially */
3434 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3436 /* User/system default languages alone are not mapped */
3437 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3438 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3440 /* Default lcids */
3441 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3442 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3443 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3444 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3445 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3446 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3449 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3450 DWORD dwFlags, LONG_PTR lParam)
3452 if (winetest_debug > 1)
3453 trace("%08x, %s, %s, %08x, %08lx\n",
3454 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3456 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3457 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3459 /* If lParam is one, we are calling with flags defaulted from 0 */
3460 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3461 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3463 return TRUE;
3466 static void test_EnumSystemLanguageGroupsA(void)
3468 BOOL ret;
3470 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3472 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3473 return;
3476 /* No enumeration proc */
3477 SetLastError(0);
3478 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3479 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3481 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3482 return;
3484 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3485 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3487 /* Invalid flags */
3488 SetLastError(0);
3489 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3490 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3492 /* No flags - defaults to LGRPID_INSTALLED */
3493 SetLastError(0xdeadbeef);
3494 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3495 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3497 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3498 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3501 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3503 if (winetest_debug > 1)
3504 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3505 return TRUE;
3508 static void test_EnumSystemLocalesEx(void)
3510 BOOL ret;
3512 if (!pEnumSystemLocalesEx)
3514 win_skip( "EnumSystemLocalesEx not available\n" );
3515 return;
3517 SetLastError( 0xdeadbeef );
3518 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3519 ok( !ret, "should have failed\n" );
3520 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3521 SetLastError( 0xdeadbeef );
3522 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3523 ok( ret, "failed err %u\n", GetLastError() );
3526 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3527 LONG_PTR lParam)
3529 if (winetest_debug > 1)
3530 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3532 /* invalid locale enumerated on some platforms */
3533 if (lcid == 0)
3534 return TRUE;
3536 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3537 "Enumerated grp %d not valid\n", lgrpid);
3538 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3539 "Enumerated grp locale %04x not valid\n", lcid);
3540 return TRUE;
3543 static void test_EnumLanguageGroupLocalesA(void)
3545 BOOL ret;
3547 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3549 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3550 return;
3553 /* No enumeration proc */
3554 SetLastError(0);
3555 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3556 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3558 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3559 return;
3561 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3562 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3564 /* lgrpid too small */
3565 SetLastError(0);
3566 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3567 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3568 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3570 /* lgrpid too big */
3571 SetLastError(0);
3572 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3573 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3574 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3576 /* dwFlags is reserved */
3577 SetLastError(0);
3578 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3579 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3580 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3582 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3585 static void test_SetLocaleInfoA(void)
3587 BOOL bRet;
3588 LCID lcid = GetUserDefaultLCID();
3590 /* Null data */
3591 SetLastError(0);
3592 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3593 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3594 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3596 /* IDATE */
3597 SetLastError(0);
3598 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3599 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3600 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3602 /* ILDATE */
3603 SetLastError(0);
3604 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3605 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3606 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3609 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3611 if (winetest_debug > 1)
3612 trace("%s %08lx\n", value, lParam);
3613 return(TRUE);
3616 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3618 ok(!enumCount, "callback called again unexpected\n");
3619 enumCount++;
3620 return(FALSE);
3623 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3625 ok(0,"callback called unexpected\n");
3626 return(FALSE);
3629 static void test_EnumUILanguageA(void)
3631 BOOL ret;
3632 if (!pEnumUILanguagesA) {
3633 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3634 return;
3637 SetLastError(ERROR_SUCCESS);
3638 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3639 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3641 win_skip("EnumUILanguagesA is not implemented\n");
3642 return;
3644 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3646 enumCount = 0;
3647 SetLastError(ERROR_SUCCESS);
3648 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3649 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3651 SetLastError(ERROR_SUCCESS);
3652 ret = pEnumUILanguagesA(NULL, 0, 0);
3653 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3654 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3655 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3657 SetLastError(ERROR_SUCCESS);
3658 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3659 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3660 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3662 SetLastError(ERROR_SUCCESS);
3663 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3664 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3665 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3666 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3669 static char date_fmt_buf[1024];
3670 static WCHAR date_fmt_bufW[1024];
3672 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3674 lstrcatA(date_fmt_buf, fmt);
3675 lstrcatA(date_fmt_buf, "\n");
3676 return TRUE;
3679 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3681 lstrcatW(date_fmt_bufW, fmt);
3682 return FALSE;
3685 static void test_EnumDateFormatsA(void)
3687 char *p, buf[256];
3688 BOOL ret;
3689 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3691 date_fmt_buf[0] = 0;
3692 SetLastError(0xdeadbeef);
3693 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3694 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3696 win_skip("0 for dwFlags is not supported\n");
3698 else
3700 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3701 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3702 /* test the 1st enumerated format */
3703 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3704 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3705 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3706 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3709 date_fmt_buf[0] = 0;
3710 SetLastError(0xdeadbeef);
3711 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3712 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3714 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3716 else
3718 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3719 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3720 /* test the 1st enumerated format */
3721 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3722 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3723 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3724 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3727 date_fmt_buf[0] = 0;
3728 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3729 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3730 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3731 /* test the 1st enumerated format */
3732 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3733 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3734 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3735 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3737 date_fmt_buf[0] = 0;
3738 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3739 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3740 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3741 /* test the 1st enumerated format */
3742 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3743 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3744 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3745 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3747 date_fmt_buf[0] = 0;
3748 SetLastError(0xdeadbeef);
3749 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3750 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3752 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3753 return;
3755 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3756 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3757 /* test the 1st enumerated format */
3758 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3759 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3760 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3761 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3762 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3765 static void test_EnumTimeFormatsA(void)
3767 char *p, buf[256];
3768 BOOL ret;
3769 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3771 date_fmt_buf[0] = 0;
3772 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3773 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3774 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3775 /* test the 1st enumerated format */
3776 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3777 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3778 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3779 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3781 date_fmt_buf[0] = 0;
3782 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3783 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3784 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3785 /* test the 1st enumerated format */
3786 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3787 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3788 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3789 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3792 static void test_EnumTimeFormatsW(void)
3794 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3795 WCHAR bufW[256];
3796 BOOL ret;
3798 date_fmt_bufW[0] = 0;
3799 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3800 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3801 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3802 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3803 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3804 wine_dbgstr_w(bufW));
3806 date_fmt_bufW[0] = 0;
3807 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3808 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3809 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3810 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3811 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3812 wine_dbgstr_w(bufW));
3814 /* TIME_NOSECONDS is Win7+ feature */
3815 date_fmt_bufW[0] = 0;
3816 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3817 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3818 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3819 else {
3820 char buf[256];
3822 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3823 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3824 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3825 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3826 wine_dbgstr_w(bufW));
3828 /* EnumTimeFormatsA doesn't support this flag */
3829 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3830 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3831 GetLastError());
3833 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3834 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3835 GetLastError());
3837 /* And it's not supported by GetLocaleInfoA either */
3838 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3839 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3840 GetLastError());
3843 static void test_GetCPInfo(void)
3845 BOOL ret;
3846 CPINFO cpinfo;
3848 SetLastError(0xdeadbeef);
3849 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3850 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3851 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3852 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3854 SetLastError(0xdeadbeef);
3855 ret = GetCPInfo(CP_UTF7, &cpinfo);
3856 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3858 win_skip("Codepage CP_UTF7 is not installed/available\n");
3860 else
3862 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3863 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3864 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3865 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3866 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3867 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3870 SetLastError(0xdeadbeef);
3871 ret = GetCPInfo(CP_UTF8, &cpinfo);
3872 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3874 win_skip("Codepage CP_UTF8 is not installed/available\n");
3876 else
3878 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3879 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3880 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3881 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3882 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3883 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3884 "expected 4, got %u\n", cpinfo.MaxCharSize);
3889 * The CT_TYPE1 has varied over windows version.
3890 * The current target for correct behavior is windows 7.
3891 * There was a big shift between windows 2000 (first introduced) and windows Xp
3892 * Most of the old values below are from windows 2000.
3893 * A smaller subset of changes happened between windows Xp and Window vista/7
3895 static void test_GetStringTypeW(void)
3897 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3898 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3899 C1_SPACE | C1_BLANK | C1_DEFINED,
3900 C1_SPACE | C1_BLANK | C1_DEFINED,
3901 C1_SPACE | C1_BLANK | C1_DEFINED,
3902 C1_CNTRL | C1_BLANK | C1_DEFINED};
3903 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3904 C1_SPACE | C1_BLANK,
3905 C1_SPACE | C1_BLANK,
3906 C1_SPACE | C1_BLANK,
3907 C1_SPACE | C1_BLANK};
3909 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3911 /* Lu, Ll, Lt */
3912 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3913 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3914 C1_LOWER | C1_ALPHA,
3915 C1_UPPER | C1_LOWER | C1_ALPHA,
3916 C1_ALPHA};
3918 /* Sk, Sk, Mn, So, Me */
3919 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3920 /* Sc, Sm, No,*/
3921 0xffe0, 0xffe9, 0x2153};
3923 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3924 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3925 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3926 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3927 C1_ALPHA | C1_DEFINED,
3928 C1_CNTRL | C1_DEFINED,
3929 C1_PUNCT | C1_DEFINED,
3930 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3931 C1_ALPHA | C1_LOWER | C1_DEFINED,
3932 C1_ALPHA | C1_DEFINED };
3933 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3934 C1_ALPHA | C1_DEFINED,
3935 C1_CNTRL | C1_DEFINED,
3936 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3937 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3938 C1_ALPHA | C1_DEFINED,
3939 C1_DEFINED
3941 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3942 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3944 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3945 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3946 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3947 static const WCHAR lower_special[] = {0x2071, 0x207f};
3948 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3949 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3950 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3951 0xfff9, 0xfffa, 0xfffb};
3952 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3954 WORD types[20];
3955 WCHAR ch[2];
3956 BOOL ret;
3957 int i;
3959 /* NULL src */
3960 SetLastError(0xdeadbeef);
3961 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3962 ok(!ret, "got %d\n", ret);
3963 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3965 SetLastError(0xdeadbeef);
3966 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3967 ok(!ret, "got %d\n", ret);
3968 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3970 SetLastError(0xdeadbeef);
3971 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3972 ok(!ret, "got %d\n", ret);
3973 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3975 memset(types,0,sizeof(types));
3976 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3977 for (i = 0; i < 5; i++)
3978 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]);
3980 memset(types,0,sizeof(types));
3981 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3982 for (i = 0; i < 3; i++)
3983 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]));
3984 memset(types,0,sizeof(types));
3985 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3986 for (i = 0; i < 5; i++)
3987 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3989 memset(types,0,sizeof(types));
3990 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3991 for (i = 0; i < 8; i++)
3992 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);
3994 memset(types,0,sizeof(types));
3995 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3996 for (i = 0; i < 7; i++)
3997 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]);
3999 memset(types,0,sizeof(types));
4000 GetStringTypeW(CT_CTYPE1, punct, 7, types);
4001 for (i = 0; i < 7; i++)
4002 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));
4005 memset(types,0,sizeof(types));
4006 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
4007 for (i = 0; i < 12; i++)
4008 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);
4010 memset(types,0,sizeof(types));
4011 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
4012 for (i = 0; i < 3; i++)
4013 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);
4015 memset(types,0,sizeof(types));
4016 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
4017 for (i = 0; i < 2; i++)
4018 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);
4020 memset(types,0,sizeof(types));
4021 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4022 for (i = 0; i < 20; i++)
4023 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);
4025 memset(types,0,sizeof(types));
4026 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4027 for (i = 0; i < 3; i++)
4028 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 );
4030 /* surrogate pairs */
4031 ch[0] = 0xd800;
4032 memset(types, 0, sizeof(types));
4033 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4034 if (types[0] == C3_NOTAPPLICABLE)
4035 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4036 else {
4037 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4039 ch[0] = 0xdc00;
4040 memset(types, 0, sizeof(types));
4041 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4042 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4045 /* Zl, Zp categories */
4046 ch[0] = 0x2028;
4047 ch[1] = 0x2029;
4048 memset(types, 0, sizeof(types));
4049 GetStringTypeW(CT_CTYPE1, ch, 2, types);
4050 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4051 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4053 /* check Arabic range for kashida flag */
4054 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4056 types[0] = 0;
4057 ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4058 ok(ret, "%#x: failed %d\n", ch[0], ret);
4059 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4060 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4061 else
4062 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4066 static void test_IdnToNameprepUnicode(void)
4068 struct {
4069 DWORD in_len;
4070 const WCHAR in[64];
4071 DWORD ret;
4072 DWORD broken_ret;
4073 const WCHAR out[64];
4074 DWORD flags;
4075 DWORD err;
4076 DWORD todo;
4077 } test_data[] = {
4079 5, {'t','e','s','t',0},
4080 5, 5, {'t','e','s','t',0},
4081 0, 0xdeadbeef
4084 3, {'a',0xe111,'b'},
4085 0, 0, {0},
4086 0, ERROR_INVALID_NAME
4089 4, {'t',0,'e',0},
4090 0, 0, {0},
4091 0, ERROR_INVALID_NAME
4094 1, {'T',0},
4095 1, 1, {'T',0},
4096 0, 0xdeadbeef
4099 1, {0},
4100 0, 0, {0},
4101 0, ERROR_INVALID_NAME
4104 6, {' ','-','/','[',']',0},
4105 6, 6, {' ','-','/','[',']',0},
4106 0, 0xdeadbeef
4109 3, {'a','-','a'},
4110 3, 3, {'a','-','a'},
4111 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4114 3, {'a','a','-'},
4115 0, 0, {0},
4116 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4118 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4119 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4120 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4121 0, 0xdeadbeef, TRUE
4124 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4125 2, 0, {'t',0},
4126 0, 0xdeadbeef
4128 { /* Another example of incorrectly working FoldString (composition) */
4129 2, {0x3b0, 0},
4130 2, 2, {0x3b0, 0},
4131 0, 0xdeadbeef, TRUE
4134 2, {0x221, 0},
4135 0, 2, {0},
4136 0, ERROR_NO_UNICODE_TRANSLATION
4139 2, {0x221, 0},
4140 2, 2, {0x221, 0},
4141 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4144 5, {'a','.','.','a',0},
4145 0, 0, {0},
4146 0, ERROR_INVALID_NAME
4149 3, {'a','.',0},
4150 3, 3, {'a','.',0},
4151 0, 0xdeadbeef
4155 WCHAR buf[1024];
4156 DWORD i, ret, err;
4158 if (!pIdnToNameprepUnicode)
4160 win_skip("IdnToNameprepUnicode is not available\n");
4161 return;
4164 ret = pIdnToNameprepUnicode(0, test_data[0].in,
4165 test_data[0].in_len, NULL, 0);
4166 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4168 SetLastError(0xdeadbeef);
4169 ret = pIdnToNameprepUnicode(0, test_data[1].in,
4170 test_data[1].in_len, NULL, 0);
4171 err = GetLastError();
4172 ok(ret == test_data[1].ret, "ret = %d\n", ret);
4173 ok(err == test_data[1].err, "err = %d\n", err);
4175 SetLastError(0xdeadbeef);
4176 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
4177 buf, sizeof(buf)/sizeof(WCHAR));
4178 err = GetLastError();
4179 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4180 ok(err == 0xdeadbeef, "err = %d\n", err);
4182 SetLastError(0xdeadbeef);
4183 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
4184 buf, sizeof(buf)/sizeof(WCHAR));
4185 err = GetLastError();
4186 ok(ret == 0, "ret = %d\n", ret);
4187 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4189 SetLastError(0xdeadbeef);
4190 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
4191 buf, sizeof(buf)/sizeof(WCHAR));
4192 err = GetLastError();
4193 ok(ret == 0, "ret = %d\n", ret);
4194 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4196 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4197 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
4198 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4200 SetLastError(0xdeadbeef);
4201 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4202 err = GetLastError();
4203 ok(ret == 0, "ret = %d\n", ret);
4204 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4206 SetLastError(0xdeadbeef);
4207 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4208 err = GetLastError();
4209 ok(ret == 0, "ret = %d\n", ret);
4210 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4211 "err = %d\n", err);
4213 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4215 SetLastError(0xdeadbeef);
4216 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
4217 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
4218 err = GetLastError();
4220 todo_wine_if (test_data[i].todo)
4221 ok(ret == test_data[i].ret ||
4222 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4224 if(ret != test_data[i].ret)
4225 continue;
4227 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4228 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4229 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4233 static void test_IdnToAscii(void)
4235 struct {
4236 DWORD in_len;
4237 const WCHAR in[64];
4238 DWORD ret;
4239 const WCHAR out[64];
4240 DWORD flags;
4241 DWORD err;
4242 } test_data[] = {
4244 5, {'T','e','s','t',0},
4245 5, {'T','e','s','t',0},
4246 0, 0xdeadbeef
4249 5, {'T','e',0x017c,'s','t',0},
4250 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4251 0, 0xdeadbeef
4254 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4255 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4256 0, 0xdeadbeef
4259 3, {0x0105,'.',0},
4260 9, {'x','n','-','-','2','d','a','.',0},
4261 0, 0xdeadbeef
4264 10, {'h','t','t','p',':','/','/','t',0x0106,0},
4265 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4266 0, 0xdeadbeef
4269 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4270 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4271 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4272 0, 0xdeadbeef
4275 2, {0x221,0},
4276 8, {'x','n','-','-','6','l','a',0},
4277 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4281 WCHAR buf[1024];
4282 DWORD i, ret, err;
4284 if (!pIdnToAscii)
4286 win_skip("IdnToAscii is not available\n");
4287 return;
4290 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4292 SetLastError(0xdeadbeef);
4293 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4294 test_data[i].in_len, buf, sizeof(buf));
4295 err = GetLastError();
4296 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4297 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4298 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4299 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4303 static void test_IdnToUnicode(void)
4305 struct {
4306 DWORD in_len;
4307 const WCHAR in[64];
4308 DWORD ret;
4309 const WCHAR out[64];
4310 DWORD flags;
4311 DWORD err;
4312 } test_data[] = {
4314 5, {'T','e','s','.',0},
4315 5, {'T','e','s','.',0},
4316 0, 0xdeadbeef
4319 2, {0x105,0},
4320 0, {0},
4321 0, ERROR_INVALID_NAME
4324 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4325 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4326 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4327 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4328 0x05d1,0x05e8,0x05d9,0x05ea,0},
4329 0, 0xdeadbeef
4332 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4333 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4334 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4335 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4336 0, 0xdeadbeef
4339 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4340 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4341 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4342 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4343 0, {0},
4344 0, ERROR_INVALID_NAME
4347 8, {'x','n','-','-','6','l','a',0},
4348 2, {0x221,0},
4349 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4353 WCHAR buf[1024];
4354 DWORD i, ret, err;
4356 if (!pIdnToUnicode)
4358 win_skip("IdnToUnicode is not available\n");
4359 return;
4362 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4364 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4365 test_data[i].in_len, NULL, 0);
4366 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4368 SetLastError(0xdeadbeef);
4369 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4370 test_data[i].in_len, buf, sizeof(buf));
4371 err = GetLastError();
4372 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4373 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4374 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4375 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4379 static void test_GetLocaleInfoEx(void)
4381 static const WCHAR enW[] = {'e','n',0};
4382 WCHAR bufferW[80], buffer2[80];
4383 INT ret;
4385 if (!pGetLocaleInfoEx)
4387 win_skip("GetLocaleInfoEx not supported\n");
4388 return;
4391 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4392 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4393 if (ret)
4395 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4396 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4397 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4398 static const WCHAR usaW[] = {'U','S','A',0};
4399 static const WCHAR enuW[] = {'E','N','U',0};
4400 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4401 DWORD val;
4403 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4404 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4406 SetLastError(0xdeadbeef);
4407 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4408 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4410 SetLastError(0xdeadbeef);
4411 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4412 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4414 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4415 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4416 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4418 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4419 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4420 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4422 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4423 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4424 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4426 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4427 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4428 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4429 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4431 skip("Non-English locale\n");
4433 else
4434 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4436 bufferW[0] = 0;
4437 SetLastError(0xdeadbeef);
4438 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4439 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4441 while (*ptr->name)
4443 val = 0;
4444 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4445 todo_wine_if (ptr->todo)
4446 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4447 bufferW[0] = 0;
4448 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4449 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4450 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4451 ptr++;
4454 ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4455 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4456 ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR));
4457 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4458 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4462 static void test_IsValidLocaleName(void)
4464 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4465 static const WCHAR zzW[] = {'z','z',0};
4466 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4467 BOOL ret;
4469 if (!pIsValidLocaleName)
4471 win_skip("IsValidLocaleName not supported\n");
4472 return;
4475 ret = pIsValidLocaleName(enusW);
4476 ok(ret, "IsValidLocaleName failed\n");
4477 ret = pIsValidLocaleName(zzW);
4478 ok(!ret, "IsValidLocaleName should have failed\n");
4479 ret = pIsValidLocaleName(zzzzW);
4480 ok(!ret, "IsValidLocaleName should have failed\n");
4481 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4482 ok(ret, "IsValidLocaleName failed\n");
4483 ret = pIsValidLocaleName(NULL);
4484 ok(!ret, "IsValidLocaleName should have failed\n");
4487 static void test_CompareStringOrdinal(void)
4489 INT ret;
4490 WCHAR test1[] = { 't','e','s','t',0 };
4491 WCHAR test2[] = { 'T','e','S','t',0 };
4492 WCHAR test3[] = { 't','e','s','t','3',0 };
4493 WCHAR null1[] = { 'a',0,'a',0 };
4494 WCHAR null2[] = { 'a',0,'b',0 };
4495 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4496 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4497 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4498 WCHAR coop2[] = { 'c','o','o','p',0 };
4499 WCHAR nonascii1[] = { 0x0102,0 };
4500 WCHAR nonascii2[] = { 0x0201,0 };
4501 WCHAR ch1, ch2;
4503 if (!pCompareStringOrdinal)
4505 win_skip("CompareStringOrdinal not supported\n");
4506 return;
4509 /* Check errors */
4510 SetLastError(0xdeadbeef);
4511 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4512 ok(!ret, "Got %u, expected 0\n", ret);
4513 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4514 SetLastError(0xdeadbeef);
4515 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4516 ok(!ret, "Got %u, expected 0\n", ret);
4517 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4518 SetLastError(0xdeadbeef);
4519 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4520 ok(!ret, "Got %u, expected 0\n", ret);
4521 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4523 /* Check case */
4524 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4525 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4526 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4527 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4528 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4529 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4530 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4531 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4533 /* Check different sizes */
4534 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4535 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4536 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4537 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4539 /* Check null character */
4540 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4541 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4542 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4543 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4544 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4545 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4546 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4547 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4549 /* Check ordinal behaviour */
4550 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4551 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4552 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4553 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4554 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4555 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4556 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4557 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4559 for (ch1 = 0; ch1 < 512; ch1++)
4561 for (ch2 = 0; ch2 < 1024; ch2++)
4563 int diff = ch1 - ch2;
4564 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4565 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4566 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4567 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4568 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4569 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4570 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4575 static void test_GetGeoInfo(void)
4577 char buffA[20];
4578 INT ret;
4580 if (!pGetGeoInfoA)
4582 win_skip("GetGeoInfo is not available.\n");
4583 return;
4586 /* unassigned id */
4587 SetLastError(0xdeadbeef);
4588 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4589 ok(ret == 0, "got %d\n", ret);
4590 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4592 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4593 ok(ret == 3, "got %d\n", ret);
4595 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4596 ok(ret == 4, "got %d\n", ret);
4598 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4599 ok(ret == 3, "got %d\n", ret);
4600 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4602 /* buffer pointer not NULL, length is 0 - return required length */
4603 buffA[0] = 'a';
4604 SetLastError(0xdeadbeef);
4605 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4606 ok(ret == 3, "got %d\n", ret);
4607 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4609 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4610 ok(ret == 4, "got %d\n", ret);
4611 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4613 /* shorter buffer */
4614 SetLastError(0xdeadbeef);
4615 buffA[1] = buffA[2] = 0;
4616 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4617 ok(ret == 0, "got %d\n", ret);
4618 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4619 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4621 /* GEO_NATION returns GEOID in a string form */
4622 buffA[0] = 0;
4623 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4624 ok(ret == 4, "got %d\n", ret);
4625 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4627 /* GEO_PARENT */
4628 buffA[0] = 0;
4629 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4630 if (ret == 0)
4631 win_skip("GEO_PARENT not supported.\n");
4632 else
4634 ok(ret == 6, "got %d\n", ret);
4635 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4638 buffA[0] = 0;
4639 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4640 if (ret == 0)
4641 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4642 else
4644 ok(ret == 4, "got %d\n", ret);
4645 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4648 /* try invalid type value */
4649 SetLastError(0xdeadbeef);
4650 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4651 ok(ret == 0, "got %d\n", ret);
4652 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4655 static int geoidenum_count;
4656 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4658 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4659 ok(ret == 3, "got %d for %d\n", ret, geoid);
4660 /* valid geoid starts at 2 */
4661 ok(geoid >= 2, "got geoid %d\n", geoid);
4663 return geoidenum_count++ < 5;
4666 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4668 geoidenum_count++;
4669 return TRUE;
4672 static void test_EnumSystemGeoID(void)
4674 BOOL ret;
4676 if (!pEnumSystemGeoID)
4678 win_skip("EnumSystemGeoID is not available.\n");
4679 return;
4682 SetLastError(0xdeadbeef);
4683 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4684 ok(!ret, "got %d\n", ret);
4685 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4687 SetLastError(0xdeadbeef);
4688 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4689 ok(!ret, "got %d\n", ret);
4690 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4692 SetLastError(0xdeadbeef);
4693 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4694 ok(!ret, "got %d\n", ret);
4695 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4697 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4698 ok(ret, "got %d\n", ret);
4700 /* only the first level is enumerated, not the whole hierarchy */
4701 geoidenum_count = 0;
4702 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4703 if (ret == 0)
4704 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4705 else
4706 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4708 geoidenum_count = 0;
4709 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4710 if (ret == 0)
4711 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4712 else
4714 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4716 geoidenum_count = 0;
4717 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4718 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4722 struct invariant_entry {
4723 const char *name;
4724 int id;
4725 const char *expect;
4728 #define X(x) #x, x
4729 static const struct invariant_entry invariant_list[] = {
4730 { X(LOCALE_ILANGUAGE), "007f" },
4731 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4732 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4733 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4734 { X(LOCALE_ICOUNTRY), "1" },
4735 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4736 { X(LOCALE_SABBREVCTRYNAME), "IVC" },
4737 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4738 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4739 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4740 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4741 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4742 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4743 { X(LOCALE_SLIST), "," },
4744 { X(LOCALE_IMEASURE), "0" },
4745 { X(LOCALE_SDECIMAL), "." },
4746 { X(LOCALE_STHOUSAND), "," },
4747 { X(LOCALE_SGROUPING), "3;0" },
4748 { X(LOCALE_IDIGITS), "2" },
4749 { X(LOCALE_ILZERO), "1" },
4750 { X(LOCALE_INEGNUMBER), "1" },
4751 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4752 { X(LOCALE_SCURRENCY), "\x00a4" },
4753 { X(LOCALE_SINTLSYMBOL), "XDR" },
4754 { X(LOCALE_SMONDECIMALSEP), "." },
4755 { X(LOCALE_SMONTHOUSANDSEP), "," },
4756 { X(LOCALE_SMONGROUPING), "3;0" },
4757 { X(LOCALE_ICURRDIGITS), "2" },
4758 { X(LOCALE_IINTLCURRDIGITS), "2" },
4759 { X(LOCALE_ICURRENCY), "0" },
4760 { X(LOCALE_INEGCURR), "0" },
4761 { X(LOCALE_SDATE), "/" },
4762 { X(LOCALE_STIME), ":" },
4763 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4764 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4765 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4766 { X(LOCALE_IDATE), "0" },
4767 { X(LOCALE_ILDATE), "1" },
4768 { X(LOCALE_ITIME), "1" },
4769 { X(LOCALE_ITIMEMARKPOSN), "0" },
4770 { X(LOCALE_ICENTURY), "1" },
4771 { X(LOCALE_ITLZERO), "1" },
4772 { X(LOCALE_IDAYLZERO), "1" },
4773 { X(LOCALE_IMONLZERO), "1" },
4774 { X(LOCALE_S1159), "AM" },
4775 { X(LOCALE_S2359), "PM" },
4776 { X(LOCALE_ICALENDARTYPE), "1" },
4777 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4778 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4779 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4780 { X(LOCALE_SDAYNAME1), "Monday" },
4781 { X(LOCALE_SDAYNAME2), "Tuesday" },
4782 { X(LOCALE_SDAYNAME3), "Wednesday" },
4783 { X(LOCALE_SDAYNAME4), "Thursday" },
4784 { X(LOCALE_SDAYNAME5), "Friday" },
4785 { X(LOCALE_SDAYNAME6), "Saturday" },
4786 { X(LOCALE_SDAYNAME7), "Sunday" },
4787 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4788 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4789 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4790 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4791 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4792 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4793 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4794 { X(LOCALE_SMONTHNAME1), "January" },
4795 { X(LOCALE_SMONTHNAME2), "February" },
4796 { X(LOCALE_SMONTHNAME3), "March" },
4797 { X(LOCALE_SMONTHNAME4), "April" },
4798 { X(LOCALE_SMONTHNAME5), "May" },
4799 { X(LOCALE_SMONTHNAME6), "June" },
4800 { X(LOCALE_SMONTHNAME7), "July" },
4801 { X(LOCALE_SMONTHNAME8), "August" },
4802 { X(LOCALE_SMONTHNAME9), "September" },
4803 { X(LOCALE_SMONTHNAME10), "October" },
4804 { X(LOCALE_SMONTHNAME11), "November" },
4805 { X(LOCALE_SMONTHNAME12), "December" },
4806 { X(LOCALE_SMONTHNAME13), "" },
4807 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4808 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4809 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4810 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4811 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4812 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4813 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4814 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4815 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4816 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4817 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4818 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4819 { X(LOCALE_SABBREVMONTHNAME13), "" },
4820 { X(LOCALE_SPOSITIVESIGN), "+" },
4821 { X(LOCALE_SNEGATIVESIGN), "-" },
4822 { X(LOCALE_IPOSSIGNPOSN), "3" },
4823 { X(LOCALE_INEGSIGNPOSN), "0" },
4824 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4825 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4826 { X(LOCALE_INEGSYMPRECEDES), "1" },
4827 { X(LOCALE_INEGSEPBYSPACE), "0" },
4828 { X(LOCALE_SISO639LANGNAME), "iv" },
4829 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4830 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4831 { X(LOCALE_IPAPERSIZE), "9" },
4832 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4833 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4834 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4835 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4836 { X(LOCALE_SNAME), "" },
4837 { X(LOCALE_SSCRIPTS), "Latn;" },
4838 { 0 }
4840 #undef X
4842 static void test_invariant(void)
4844 int ret;
4845 int len;
4846 char buffer[BUFFER_SIZE];
4847 const struct invariant_entry *ptr = invariant_list;
4849 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4851 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4852 return;
4855 while (ptr->name)
4857 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4858 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4859 win_skip("not supported\n"); /* winxp/win2k3 */
4860 else
4862 len = strlen(ptr->expect)+1; /* include \0 */
4863 ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
4864 ptr->id, len, ret, GetLastError());
4865 ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
4866 ptr->id, ptr->expect, buffer);
4869 ptr++;
4872 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4873 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4875 skip("Non-English locale\n");
4877 else
4879 /* some locales translate these */
4880 static const char lang[] = "Invariant Language (Invariant Country)";
4881 static const char cntry[] = "Invariant Country";
4882 static const char sortm[] = "Math Alphanumerics";
4883 static const char sortd[] = "Default"; /* win2k3 */
4885 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4886 len = lstrlenA(lang) + 1;
4887 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4888 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4890 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4891 len = lstrlenA(cntry) + 1;
4892 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4893 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4895 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4896 if (ret == lstrlenA(sortm)+1)
4897 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4898 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4899 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4900 else
4901 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4902 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4906 static void test_GetSystemPreferredUILanguages(void)
4908 BOOL ret;
4909 ULONG count, size, size_id, size_name, size_buffer;
4910 WCHAR *buffer;
4913 if (!pGetSystemPreferredUILanguages)
4915 win_skip("GetSystemPreferredUILanguages is not available.\n");
4916 return;
4919 /* (in)valid first parameter */
4920 count = 0xdeadbeef;
4921 size = 0;
4922 SetLastError(0xdeadbeef);
4923 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4924 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4925 ok(count, "Expected count > 0\n");
4926 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4928 count = 0xdeadbeef;
4929 size = 0;
4930 SetLastError(0xdeadbeef);
4931 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4932 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4933 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4934 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4936 count = 0xdeadbeef;
4937 size = 0;
4938 SetLastError(0xdeadbeef);
4939 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4940 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4941 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4942 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4944 count = 0xdeadbeef;
4945 size = 0;
4946 SetLastError(0xdeadbeef);
4947 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
4948 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4949 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4950 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4952 count = 0xdeadbeef;
4953 size = 0;
4954 SetLastError(0xdeadbeef);
4955 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4956 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4957 ok(count, "Expected count > 0\n");
4958 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4960 count = 0xdeadbeef;
4961 size = 0;
4962 SetLastError(0xdeadbeef);
4963 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4964 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4965 ok(count, "Expected count > 0\n");
4966 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4968 /* second parameter
4969 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
4970 * -> unhandled exception c0000005
4973 /* invalid third parameter */
4974 count = 0xdeadbeef;
4975 size = 1;
4976 SetLastError(0xdeadbeef);
4977 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
4978 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4979 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4980 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4982 /* fourth parameter
4983 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
4984 * -> unhandled exception c0000005
4987 count = 0xdeadbeef;
4988 size_id = 0;
4989 SetLastError(0xdeadbeef);
4990 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
4991 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4992 ok(count, "Expected count > 0\n");
4993 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
4995 count = 0xdeadbeef;
4996 size_name = 0;
4997 SetLastError(0xdeadbeef);
4998 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
4999 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5000 ok(count, "Expected count > 0\n");
5001 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5003 size_buffer = max(size_id, size_name);
5004 if(!size_buffer)
5006 skip("No valid buffer size\n");
5007 return;
5010 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5011 if (!buffer)
5013 skip("Failed to allocate memory for %d chars\n", size_buffer);
5014 return;
5017 count = 0xdeadbeef;
5018 size = size_buffer;
5019 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5020 SetLastError(0xdeadbeef);
5021 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5022 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5023 ok(count, "Expected count > 0\n");
5024 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5025 if (ret && size % 6 == 1)
5026 ok(!buffer[size -2] && !buffer[size -1],
5027 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5028 buffer[size -2], buffer[size -1]);
5030 count = 0xdeadbeef;
5031 size = size_buffer;
5032 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5033 SetLastError(0xdeadbeef);
5034 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5035 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5036 ok(count, "Expected count > 0\n");
5037 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5038 if (ret && size % 5 == 1)
5039 ok(!buffer[size -2] && !buffer[size -1],
5040 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5041 buffer[size -2], buffer[size -1]);
5043 count = 0xdeadbeef;
5044 size = size_buffer;
5045 SetLastError(0xdeadbeef);
5046 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5047 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5048 ok(count, "Expected count > 0\n");
5049 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5050 if (ret && size % 5 == 1)
5051 ok(!buffer[size -2] && !buffer[size -1],
5052 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5053 buffer[size -2], buffer[size -1]);
5055 count = 0xdeadbeef;
5056 size = 0;
5057 SetLastError(0xdeadbeef);
5058 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5059 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5060 ok(count, "Expected count > 0\n");
5061 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5062 if (ret && size % 6 == 1)
5063 ok(!buffer[size -2] && !buffer[size -1],
5064 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5065 buffer[size -2], buffer[size -1]);
5067 count = 0xdeadbeef;
5068 size = 1;
5069 SetLastError(0xdeadbeef);
5070 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5071 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5072 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5073 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5075 count = 0xdeadbeef;
5076 size = size_id -1;
5077 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5078 SetLastError(0xdeadbeef);
5079 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5080 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5081 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5082 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5084 count = 0xdeadbeef;
5085 size = size_id -2;
5086 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5087 SetLastError(0xdeadbeef);
5088 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5089 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5090 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5091 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5093 HeapFree(GetProcessHeap(), 0, buffer);
5096 static void test_GetThreadPreferredUILanguages(void)
5098 BOOL ret;
5099 ULONG count, size;
5100 WCHAR *buf;
5102 if (!pGetThreadPreferredUILanguages)
5104 win_skip("GetThreadPreferredUILanguages is not available.\n");
5105 return;
5108 size = count = 0;
5109 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5110 ok(ret, "got %u\n", GetLastError());
5111 ok(count, "expected count > 0\n");
5112 ok(size, "expected size > 0\n");
5114 count = 0;
5115 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5116 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5117 ok(ret, "got %u\n", GetLastError());
5118 ok(count, "expected count > 0\n");
5119 HeapFree(GetProcessHeap(), 0, buf);
5122 static void test_GetUserPreferredUILanguages(void)
5124 BOOL ret;
5125 ULONG count, size, size_id, size_name, size_buffer;
5126 WCHAR *buffer;
5129 if (!pGetUserPreferredUILanguages)
5131 win_skip("GetUserPreferredUILanguages is not available.\n");
5132 return;
5135 count = 0xdeadbeef;
5136 size = 0;
5137 SetLastError(0xdeadbeef);
5138 ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5139 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5140 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5141 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5143 count = 0xdeadbeef;
5144 size = 0;
5145 SetLastError(0xdeadbeef);
5146 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5147 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5148 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5149 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5151 count = 0xdeadbeef;
5152 size = 0;
5153 SetLastError(0xdeadbeef);
5154 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5155 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5156 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5157 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5159 count = 0xdeadbeef;
5160 size = 1;
5161 SetLastError(0xdeadbeef);
5162 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5163 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5164 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5165 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5167 count = 0xdeadbeef;
5168 size_id = 0;
5169 SetLastError(0xdeadbeef);
5170 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5171 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5172 ok(count, "Expected count > 0\n");
5173 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5175 count = 0xdeadbeef;
5176 size_name = 0;
5177 SetLastError(0xdeadbeef);
5178 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5179 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5180 ok(count, "Expected count > 0\n");
5181 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5183 size_buffer = max(size_id, size_name);
5184 if(!size_buffer)
5186 skip("No valid buffer size\n");
5187 return;
5190 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5192 count = 0xdeadbeef;
5193 size = size_buffer;
5194 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5195 SetLastError(0xdeadbeef);
5196 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5197 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5198 ok(count, "Expected count > 0\n");
5199 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5200 if (ret && size % 6 == 1)
5201 ok(!buffer[size -2] && !buffer[size -1],
5202 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5203 buffer[size -2], buffer[size -1]);
5205 count = 0xdeadbeef;
5206 size = size_buffer;
5207 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5208 SetLastError(0xdeadbeef);
5209 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5210 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5211 ok(count, "Expected count > 0\n");
5212 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5213 if (ret && size % 5 == 1)
5214 ok(!buffer[size -2] && !buffer[size -1],
5215 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5216 buffer[size -2], buffer[size -1]);
5218 count = 0xdeadbeef;
5219 size = size_buffer;
5220 SetLastError(0xdeadbeef);
5221 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5222 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5223 ok(count, "Expected count > 0\n");
5224 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5225 if (ret && size % 5 == 1)
5226 ok(!buffer[size -2] && !buffer[size -1],
5227 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5228 buffer[size -2], buffer[size -1]);
5230 count = 0xdeadbeef;
5231 size = 1;
5232 SetLastError(0xdeadbeef);
5233 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5234 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5235 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5236 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5238 count = 0xdeadbeef;
5239 size = size_id -1;
5240 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5241 SetLastError(0xdeadbeef);
5242 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5243 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5244 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5245 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5247 count = 0xdeadbeef;
5248 size = size_id -2;
5249 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5250 SetLastError(0xdeadbeef);
5251 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5252 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5253 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5254 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5256 HeapFree(GetProcessHeap(), 0, buffer);
5259 START_TEST(locale)
5261 InitFunctionPointers();
5263 test_EnumTimeFormatsA();
5264 test_EnumTimeFormatsW();
5265 test_EnumDateFormatsA();
5266 test_GetLocaleInfoA();
5267 test_GetLocaleInfoW();
5268 test_GetLocaleInfoEx();
5269 test_GetTimeFormatA();
5270 test_GetTimeFormatEx();
5271 test_GetDateFormatA();
5272 test_GetDateFormatEx();
5273 test_GetDateFormatW();
5274 test_GetCurrencyFormatA(); /* Also tests the W version */
5275 test_GetNumberFormatA(); /* Also tests the W version */
5276 test_GetNumberFormatEx();
5277 test_CompareStringA();
5278 test_CompareStringW();
5279 test_CompareStringEx();
5280 test_LCMapStringA();
5281 test_LCMapStringW();
5282 test_LCMapStringEx();
5283 test_LocaleNameToLCID();
5284 test_FoldStringA();
5285 test_FoldStringW();
5286 test_ConvertDefaultLocale();
5287 test_EnumSystemLanguageGroupsA();
5288 test_EnumSystemLocalesEx();
5289 test_EnumLanguageGroupLocalesA();
5290 test_SetLocaleInfoA();
5291 test_EnumUILanguageA();
5292 test_GetCPInfo();
5293 test_GetStringTypeW();
5294 test_IdnToNameprepUnicode();
5295 test_IdnToAscii();
5296 test_IdnToUnicode();
5297 test_IsValidLocaleName();
5298 test_CompareStringOrdinal();
5299 test_GetGeoInfo();
5300 test_EnumSystemGeoID();
5301 test_invariant();
5302 test_GetSystemPreferredUILanguages();
5303 test_GetThreadPreferredUILanguages();
5304 test_GetUserPreferredUILanguages();
5305 /* this requires collation table patch to make it MS compatible */
5306 if (0) test_sorting();