kernel32/tests: Use WINAPIV calling convention for variadic functions.
[wine.git] / dlls / kernel32 / tests / locale.c
blob86fcc33b709b04493b00f1b6764de383d0cdb1ef
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};
46 static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
48 static inline unsigned int strlenW( const WCHAR *str )
50 const WCHAR *s = str;
51 while (*s) s++;
52 return s - str;
55 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
57 if (n <= 0) return 0;
58 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
59 return *str1 - *str2;
62 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
64 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
65 return NULL;
68 static inline BOOL isdigitW( WCHAR wc )
70 WORD type;
71 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
72 return type & C1_DIGIT;
75 /* Some functions are only in later versions of kernel32.dll */
76 static WORD enumCount;
78 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
79 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
80 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
83 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
84 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
85 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
86 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
87 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
88 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
90 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
93 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
94 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
95 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
96 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
97 LPNLSVERSIONINFO, LPVOID, LPARAM);
98 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
99 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
100 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
101 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
103 static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
104 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
105 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
107 static void InitFunctionPointers(void)
109 HMODULE mod = GetModuleHandleA("kernel32");
111 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
112 X(GetTimeFormatEx);
113 X(GetDateFormatEx);
114 X(EnumSystemLanguageGroupsA);
115 X(EnumLanguageGroupLocalesA);
116 X(LocaleNameToLCID);
117 X(LCIDToLocaleName);
118 X(LCMapStringEx);
119 X(FoldStringA);
120 X(FoldStringW);
121 X(IsValidLanguageGroup);
122 X(EnumUILanguagesA);
123 X(EnumSystemLocalesEx);
124 X(IdnToNameprepUnicode);
125 X(IdnToAscii);
126 X(IdnToUnicode);
127 X(GetLocaleInfoEx);
128 X(IsValidLocaleName);
129 X(CompareStringOrdinal);
130 X(CompareStringEx);
131 X(GetGeoInfoA);
132 X(GetGeoInfoW);
133 X(EnumSystemGeoID);
134 X(GetSystemPreferredUILanguages);
135 X(GetThreadPreferredUILanguages);
136 X(GetUserPreferredUILanguages);
137 X(GetNumberFormatEx);
139 mod = GetModuleHandleA("ntdll");
140 X(RtlUpcaseUnicodeChar);
141 #undef X
144 #define eq(received, expected, label, type) \
145 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
146 (label), (received), (expected))
148 #define BUFFER_SIZE 128
149 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
151 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
152 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
153 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
154 "Expected '%s', got '%s'\n", Expected, buffer)
156 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
157 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
158 SetLastError(0xdeadbeef); buffer[0] = '\0'
159 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
160 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
162 #define NUO LOCALE_NOUSEROVERRIDE
164 static void test_GetLocaleInfoA(void)
166 int ret;
167 int len;
168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
169 char buffer[BUFFER_SIZE];
170 char expected[BUFFER_SIZE];
171 DWORD val;
173 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
175 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
176 ok(ret, "got %d\n", ret);
177 ok(val == lcid, "got 0x%08x\n", val);
179 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
180 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
181 assumes SUBLANG_NEUTRAL for zh */
182 memset(expected, 0, COUNTOF(expected));
183 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
184 SetLastError(0xdeadbeef);
185 memset(buffer, 0, COUNTOF(buffer));
186 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
187 ok((ret == len) && !lstrcmpA(buffer, expected),
188 "got %d with '%s' (expected %d with '%s')\n",
189 ret, buffer, len, expected);
191 memset(expected, 0, COUNTOF(expected));
192 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
193 if (len) {
194 SetLastError(0xdeadbeef);
195 memset(buffer, 0, COUNTOF(buffer));
196 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
197 ok((ret == len) && !lstrcmpA(buffer, expected),
198 "got %d with '%s' (expected %d with '%s')\n",
199 ret, buffer, len, expected);
201 else
202 win_skip("LANG_ARABIC not installed\n");
204 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
205 memset(expected, 0, COUNTOF(expected));
206 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
207 SetLastError(0xdeadbeef);
208 memset(buffer, 0, COUNTOF(buffer));
209 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
210 ok((ret == len) && !lstrcmpA(buffer, expected),
211 "got %d with '%s' (expected %d with '%s')\n",
212 ret, buffer, len, expected);
215 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
216 * partially fill the buffer even if it is too short. See bug 637.
218 SetLastError(0xdeadbeef);
219 memset(buffer, 0, COUNTOF(buffer));
220 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
221 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
223 SetLastError(0xdeadbeef);
224 memset(buffer, 0, COUNTOF(buffer));
225 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
226 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
227 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
228 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
230 SetLastError(0xdeadbeef);
231 memset(buffer, 0, COUNTOF(buffer));
232 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
233 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
234 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
237 struct neutralsublang_name2_t {
238 WCHAR name[3];
239 WCHAR sname[15];
240 LCID lcid;
241 LCID lcid_broken;
242 WCHAR sname_broken[15];
243 int todo;
246 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
247 { {'a','r',0}, {'a','r','-','S','A',0},
248 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
249 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
250 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
251 { {'d','e',0}, {'d','e','-','D','E',0},
252 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
253 { {'e','n',0}, {'e','n','-','U','S',0},
254 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
255 { {'e','s',0}, {'e','s','-','E','S',0},
256 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
257 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
258 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
259 { {'g','a',0}, {'g','a','-','I','E',0},
260 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
261 { {'i','t',0}, {'i','t','-','I','T',0},
262 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
263 { {'m','s',0}, {'m','s','-','M','Y',0},
264 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
265 { {'n','l',0}, {'n','l','-','N','L',0},
266 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
267 { {'p','t',0}, {'p','t','-','B','R',0},
268 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
269 { {'s','r',0}, {'h','r','-','H','R',0},
270 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
271 { {'s','v',0}, {'s','v','-','S','E',0},
272 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
273 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
274 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
275 { {'z','h',0}, {'z','h','-','C','N',0},
276 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
277 { {0} }
280 static void test_GetLocaleInfoW(void)
282 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
283 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
284 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
285 WCHAR bufferW[80], buffer2W[80];
286 CHAR bufferA[80];
287 DWORD val;
288 DWORD ret;
289 INT i;
291 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
292 if (!ret) {
293 win_skip("GetLocaleInfoW() isn't implemented\n");
294 return;
297 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
298 ok(ret, "got %d\n", ret);
299 ok(val == lcid_en, "got 0x%08x\n", val);
301 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
302 if (ret)
304 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
305 'S','t','a','t','e','s',')',0};
306 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
307 static const WCHAR enW[] = {'e','n','-','U','S',0};
308 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
310 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
312 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
313 ok(ret, "got %d\n", ret);
314 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
315 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
317 skip("Non-English locale\n");
319 else
320 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
322 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
323 ok(ret, "got %d\n", ret);
324 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
325 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
327 skip("Non-English locale\n");
329 else
330 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
332 while (*ptr->name)
334 LANGID langid;
335 LCID lcid;
337 /* make neutral lcid */
338 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
339 lcid = MAKELCID(langid, SORT_DEFAULT);
341 val = 0;
342 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
343 todo_wine_if (ptr->todo & 0x1)
344 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
345 wine_dbgstr_w(ptr->name), val, ptr->lcid);
347 /* now check LOCALE_SNAME */
348 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
349 todo_wine_if (ptr->todo & 0x2)
350 ok(!lstrcmpW(bufferW, ptr->sname) ||
351 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
352 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
353 ptr++;
356 else
357 win_skip("English neutral locale not supported\n");
359 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
360 if (!ret) {
361 win_skip("LANG_RUSSIAN locale data unavailable\n");
362 return;
364 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
365 bufferW, COUNTOF(bufferW));
366 if (!ret) {
367 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
368 return;
371 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
372 bufferA[0] = 'a';
373 SetLastError(0xdeadbeef);
374 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
375 bufferA, COUNTOF(bufferA));
376 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
377 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
378 ok(GetLastError() == ERROR_INVALID_FLAGS,
379 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
381 bufferW[0] = 'a';
382 SetLastError(0xdeadbeef);
383 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
384 bufferW, COUNTOF(bufferW));
385 ok(ret == 0,
386 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
387 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
388 ok(GetLastError() == ERROR_INVALID_FLAGS,
389 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
391 /* yes, test empty 13 month entry too */
392 for (i = 0; i < 12; i++) {
393 bufferW[0] = 0;
394 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
395 bufferW, COUNTOF(bufferW));
396 ok(ret, "Expected non zero result\n");
397 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
398 ret, lstrlenW(bufferW));
399 buffer2W[0] = 0;
400 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
401 buffer2W, COUNTOF(buffer2W));
402 ok(ret, "Expected non zero result\n");
403 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
404 ret, lstrlenW(buffer2W));
406 ok(lstrcmpW(bufferW, buffer2W) != 0,
407 "Expected genitive name to differ, got the same for month %d\n", i+1);
409 /* for locale without genitive names nominative returned in both cases */
410 bufferW[0] = 0;
411 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
412 bufferW, COUNTOF(bufferW));
413 ok(ret, "Expected non zero result\n");
414 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
415 ret, lstrlenW(bufferW));
416 buffer2W[0] = 0;
417 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
418 buffer2W, COUNTOF(buffer2W));
419 ok(ret, "Expected non zero result\n");
420 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
421 ret, lstrlenW(buffer2W));
423 ok(lstrcmpW(bufferW, buffer2W) == 0,
424 "Expected same names, got different for month %d\n", i+1);
428 static void test_GetTimeFormatA(void)
430 int ret;
431 SYSTEMTIME curtime;
432 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
433 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
435 memset(&curtime, 2, sizeof(SYSTEMTIME));
436 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
437 SetLastError(0xdeadbeef);
438 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
442 curtime.wHour = 8;
443 curtime.wMinute = 56;
444 curtime.wSecond = 13;
445 curtime.wMilliseconds = 22;
446 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
447 SetLastError(0xdeadbeef);
448 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
450 EXPECT_LENA; EXPECT_EQA;
452 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
453 SetLastError(0xdeadbeef);
454 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
455 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
456 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
458 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
459 SetLastError(0xdeadbeef);
460 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
461 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
462 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
464 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
465 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
466 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
467 EXPECT_LENA;
469 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
470 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
472 EXPECT_LENA; EXPECT_EQA;
474 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
475 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
476 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
477 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
478 "Expected '', got '%s'\n", buffer );
480 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
481 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 EXPECT_LENA; EXPECT_EQA;
485 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
486 strcpy(Expected, "8:56 AM");
487 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
488 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
489 EXPECT_LENA; EXPECT_EQA;
491 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
492 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
493 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
494 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
495 "Expected '8.@:56AM', got '%s'\n", buffer );
497 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
498 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
499 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
500 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
501 "Expected '', got '%s'\n", buffer );
503 STRINGSA("t/tt", "A/AM"); /* AM time marker */
504 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
505 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
506 EXPECT_LENA; EXPECT_EQA;
508 curtime.wHour = 13;
509 STRINGSA("t/tt", "P/PM"); /* PM time marker */
510 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
512 EXPECT_LENA; EXPECT_EQA;
514 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
515 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
516 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
517 EXPECT_LENA; EXPECT_EQA;
519 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
520 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
521 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
522 EXPECT_LENA; EXPECT_EQA;
524 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
525 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
527 EXPECT_LENA; EXPECT_EQA;
529 curtime.wHour = 14; /* change this to 14 or 2pm */
530 curtime.wMinute = 5;
531 curtime.wSecond = 3;
532 STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
533 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
534 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
535 EXPECT_LENA; EXPECT_EQA;
537 curtime.wHour = 0;
538 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
539 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
540 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
541 EXPECT_LENA; EXPECT_EQA;
543 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
544 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
545 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
546 EXPECT_LENA; EXPECT_EQA;
548 /* try to convert formatting strings with more than two letters
549 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
550 * NOTE: We expect any letter for which there is an upper case value
551 * we should see a replacement. For letters that DO NOT have
552 * upper case values we should see NO REPLACEMENT.
554 curtime.wHour = 8;
555 curtime.wMinute = 56;
556 curtime.wSecond = 13;
557 curtime.wMilliseconds = 22;
558 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
559 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
560 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 EXPECT_LENA; EXPECT_EQA;
564 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
565 strcpy(buffer, "text");
566 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
567 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
568 EXPECT_EQA;
570 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
571 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
572 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
573 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
574 EXPECT_LENA; EXPECT_EQA;
576 STRINGSA("'''", "'"); /* invalid quoted string */
577 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
579 EXPECT_LENA; EXPECT_EQA;
581 /* test that msdn suggested single quotation usage works as expected */
582 STRINGSA("''''", "'"); /* single quote mark */
583 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
585 EXPECT_LENA; EXPECT_EQA;
587 STRINGSA("''HHHHHH", "08"); /* Normal use */
588 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
589 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
590 EXPECT_LENA; EXPECT_EQA;
592 /* and test for normal use of the single quotation mark */
593 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
594 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
595 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
596 EXPECT_LENA; EXPECT_EQA;
598 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
599 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
600 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
601 EXPECT_LENA; EXPECT_EQA;
603 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
604 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
605 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
606 EXPECT_LENA; EXPECT_EQA;
608 curtime.wHour = 25;
609 STRINGSA("'123'tt", ""); /* Invalid time */
610 SetLastError(0xdeadbeef);
611 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
612 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
613 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
615 curtime.wHour = 12;
616 curtime.wMonth = 60; /* Invalid */
617 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
618 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
619 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
620 EXPECT_LENA; EXPECT_EQA;
623 static void test_GetTimeFormatEx(void)
625 int ret;
626 SYSTEMTIME curtime;
627 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
629 if (!pGetTimeFormatEx)
631 win_skip("GetTimeFormatEx not supported\n");
632 return;
635 memset(&curtime, 2, sizeof(SYSTEMTIME));
636 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
637 SetLastError(0xdeadbeef);
638 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
639 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
640 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
642 curtime.wHour = 8;
643 curtime.wMinute = 56;
644 curtime.wSecond = 13;
645 curtime.wMilliseconds = 22;
646 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
647 SetLastError(0xdeadbeef);
648 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
649 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
650 EXPECT_LENW; EXPECT_EQW;
652 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
653 SetLastError(0xdeadbeef);
654 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
655 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
656 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
658 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
659 SetLastError(0xdeadbeef);
660 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
661 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
662 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
664 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
665 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
666 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
667 EXPECT_LENW;
669 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
670 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
672 EXPECT_LENW; EXPECT_EQW;
674 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
675 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
676 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
677 EXPECT_LENW; EXPECT_EQW;
679 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
680 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
682 EXPECT_LENW; EXPECT_EQW;
684 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
685 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
686 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
687 EXPECT_LENW; EXPECT_EQW;
689 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
690 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
691 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
692 EXPECT_LENW; EXPECT_EQW;
694 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
695 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
696 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
697 EXPECT_LENW; EXPECT_EQW;
699 STRINGSW("t/tt", "A/AM"); /* AM time marker */
700 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 EXPECT_LENW; EXPECT_EQW;
704 curtime.wHour = 13;
705 STRINGSW("t/tt", "P/PM"); /* PM time marker */
706 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 EXPECT_LENW; EXPECT_EQW;
710 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
711 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 EXPECT_LENW; EXPECT_EQW;
715 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
716 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
718 EXPECT_LENW; EXPECT_EQW;
720 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
721 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
722 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
723 EXPECT_LENW; EXPECT_EQW;
725 curtime.wHour = 14; /* change this to 14 or 2pm */
726 curtime.wMinute = 5;
727 curtime.wSecond = 3;
728 STRINGSW("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
729 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
730 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
731 EXPECT_LENW; EXPECT_EQW;
733 curtime.wHour = 0;
734 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
735 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
736 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
737 EXPECT_LENW; EXPECT_EQW;
739 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
740 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
741 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
742 EXPECT_LENW; EXPECT_EQW;
744 /* try to convert formatting strings with more than two letters
745 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
746 * NOTE: We expect any letter for which there is an upper case value
747 * we should see a replacement. For letters that DO NOT have
748 * upper case values we should see NO REPLACEMENT.
750 curtime.wHour = 8;
751 curtime.wMinute = 56;
752 curtime.wSecond = 13;
753 curtime.wMilliseconds = 22;
754 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
755 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
756 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
757 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
758 EXPECT_LENW; EXPECT_EQW;
760 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
761 lstrcpyW(buffer, Expected);
762 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
763 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
764 EXPECT_EQW;
766 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
767 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
768 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
769 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
770 EXPECT_LENW; EXPECT_EQW;
772 STRINGSW("'''", "'"); /* invalid quoted string */
773 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
774 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
775 EXPECT_LENW; EXPECT_EQW;
777 /* test that msdn suggested single quotation usage works as expected */
778 STRINGSW("''''", "'"); /* single quote mark */
779 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
780 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781 EXPECT_LENW; EXPECT_EQW;
783 STRINGSW("''HHHHHH", "08"); /* Normal use */
784 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENW; EXPECT_EQW;
788 /* and test for normal use of the single quotation mark */
789 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
790 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
791 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
792 EXPECT_LENW; EXPECT_EQW;
794 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
795 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
796 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
797 EXPECT_LENW; EXPECT_EQW;
799 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
800 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
801 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
802 EXPECT_LENW; EXPECT_EQW;
804 curtime.wHour = 25;
805 STRINGSW("'123'tt", ""); /* Invalid time */
806 SetLastError(0xdeadbeef);
807 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
808 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
809 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
811 curtime.wHour = 12;
812 curtime.wMonth = 60; /* Invalid */
813 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
814 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
815 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
816 EXPECT_LENW; EXPECT_EQW;
819 static void test_GetDateFormatA(void)
821 int ret;
822 SYSTEMTIME curtime;
823 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
824 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
825 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
826 char Broken[BUFFER_SIZE];
827 char short_day[10], month[10], genitive_month[10];
829 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
830 STRINGSA("ddd',' MMM dd yy","");
831 SetLastError(0xdeadbeef);
832 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
833 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
834 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
836 curtime.wYear = 2002;
837 curtime.wMonth = 5;
838 curtime.wDay = 4;
839 curtime.wDayOfWeek = 3;
840 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
841 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
842 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
843 EXPECT_LENA; EXPECT_EQA;
845 /* Same as above but with LOCALE_NOUSEROVERRIDE */
846 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
847 SetLastError(0xdeadbeef);
848 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
849 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
850 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
851 EXPECT_EQA;
853 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
854 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
855 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
856 EXPECT_LENA; EXPECT_EQA;
858 curtime.wHour = 36; /* Invalid */
859 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
860 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
861 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
862 EXPECT_LENA; EXPECT_EQA;
864 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
865 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
866 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
867 EXPECT_EQA;
869 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
870 SetLastError(0xdeadbeef);
871 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
872 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
873 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
875 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
876 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
877 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
878 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
879 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
881 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
882 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
883 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
884 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
885 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
886 "got an unexpected date string '%s'\n", buffer);
888 /* test for expected DATE_YEARMONTH behavior with null format */
889 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
890 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
891 SetLastError(0xdeadbeef);
892 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
893 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
894 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 EXPECT_EQA;
897 /* Test that using invalid DATE_* flags results in the correct error */
898 /* and return values */
899 STRINGSA("m/d/y", ""); /* Invalid flags */
900 SetLastError(0xdeadbeef);
901 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
902 &curtime, input, buffer, COUNTOF(buffer));
903 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
904 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
906 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
907 if (!ret)
909 win_skip("LANG_RUSSIAN locale data unavailable\n");
910 return;
913 /* month part should be in genitive form */
914 strcpy(genitive_month, buffer + 2);
915 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 strcpy(month, buffer);
918 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
920 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
921 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
922 strcpy(short_day, buffer);
924 STRINGSA("dd MMMMddd dd", "");
925 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
926 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
927 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
928 EXPECT_EQA;
930 STRINGSA("MMMMddd dd", "");
931 sprintf(Expected, "%s%s 04", month, short_day);
932 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
933 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
934 EXPECT_EQA;
936 STRINGSA("MMMMddd", "");
937 sprintf(Expected, "%s%s", month, short_day);
938 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
939 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
940 EXPECT_EQA;
942 STRINGSA("MMMMdd", "");
943 sprintf(Expected, "%s04", genitive_month);
944 sprintf(Broken, "%s04", month);
945 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
948 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
949 "Expected '%s', got '%s'\n", Expected, buffer);
951 STRINGSA("MMMMdd ddd", "");
952 sprintf(Expected, "%s04 %s", genitive_month, short_day);
953 sprintf(Broken, "%s04 %s", month, short_day);
954 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
955 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
956 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
957 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
958 "Expected '%s', got '%s'\n", Expected, buffer);
960 STRINGSA("dd dddMMMM", "");
961 sprintf(Expected, "04 %s%s", short_day, month);
962 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
963 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
964 EXPECT_EQA;
966 STRINGSA("dd dddMMMM ddd MMMMdd", "");
967 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
968 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
969 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
970 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
971 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
972 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
973 "Expected '%s', got '%s'\n", Expected, buffer);
975 /* with literal part */
976 STRINGSA("ddd',' MMMM dd", "");
977 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
978 sprintf(Broken, "%s, %s 04", short_day, month);
979 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
980 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
981 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
982 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
983 "Expected '%s', got '%s'\n", Expected, buffer);
986 static void test_GetDateFormatEx(void)
988 int ret;
989 SYSTEMTIME curtime;
990 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
992 if (!pGetDateFormatEx)
994 win_skip("GetDateFormatEx not supported\n");
995 return;
998 STRINGSW("",""); /* If flags are set, then format must be NULL */
999 SetLastError(0xdeadbeef);
1000 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1001 input, buffer, COUNTOF(buffer), NULL);
1002 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1003 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1004 EXPECT_EQW;
1006 STRINGSW("",""); /* NULL buffer, len > 0 */
1007 SetLastError(0xdeadbeef);
1008 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1009 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1010 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1012 STRINGSW("",""); /* NULL buffer, len == 0 */
1013 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1014 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1015 EXPECT_LENW; EXPECT_EQW;
1017 STRINGSW("",""); /* Invalid flag combination */
1018 SetLastError(0xdeadbeef);
1019 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1020 input, NULL, 0, NULL);
1021 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1022 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1023 EXPECT_EQW;
1025 curtime.wYear = 2002;
1026 curtime.wMonth = 10;
1027 curtime.wDay = 23;
1028 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1029 curtime.wHour = 65432; /* Invalid */
1030 curtime.wMinute = 34512; /* Invalid */
1031 curtime.wSecond = 65535; /* Invalid */
1032 curtime.wMilliseconds = 12345;
1033 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1034 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1036 EXPECT_LENW; EXPECT_EQW;
1038 curtime.wYear = 2002;
1039 curtime.wMonth = 10;
1040 curtime.wDay = 23;
1041 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1042 curtime.wHour = 65432; /* Invalid */
1043 curtime.wMinute = 34512; /* Invalid */
1044 curtime.wSecond = 65535; /* Invalid */
1045 curtime.wMilliseconds = 12345;
1046 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1047 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1048 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1049 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1051 /* Limit tests */
1053 curtime.wYear = 1601;
1054 curtime.wMonth = 1;
1055 curtime.wDay = 1;
1056 curtime.wDayOfWeek = 0; /* Irrelevant */
1057 curtime.wHour = 0;
1058 curtime.wMinute = 0;
1059 curtime.wSecond = 0;
1060 curtime.wMilliseconds = 0;
1061 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1062 SetLastError(0xdeadbeef);
1063 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1064 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1065 EXPECT_LENW; EXPECT_EQW;
1067 curtime.wYear = 1600;
1068 curtime.wMonth = 12;
1069 curtime.wDay = 31;
1070 curtime.wDayOfWeek = 0; /* Irrelevant */
1071 curtime.wHour = 23;
1072 curtime.wMinute = 59;
1073 curtime.wSecond = 59;
1074 curtime.wMilliseconds = 999;
1075 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1076 SetLastError(0xdeadbeef);
1077 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1078 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1079 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1082 static void test_GetDateFormatW(void)
1084 int ret;
1085 SYSTEMTIME curtime;
1086 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1087 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1089 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1090 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1091 input, buffer, COUNTOF(buffer));
1092 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1094 win_skip("GetDateFormatW is not implemented\n");
1095 return;
1097 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1098 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1099 EXPECT_EQW;
1101 STRINGSW("",""); /* NULL buffer, len > 0 */
1102 SetLastError(0xdeadbeef);
1103 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1104 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1105 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1107 STRINGSW("",""); /* NULL buffer, len == 0 */
1108 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENW; EXPECT_EQW;
1112 curtime.wYear = 2002;
1113 curtime.wMonth = 10;
1114 curtime.wDay = 23;
1115 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1116 curtime.wHour = 65432; /* Invalid */
1117 curtime.wMinute = 34512; /* Invalid */
1118 curtime.wSecond = 65535; /* Invalid */
1119 curtime.wMilliseconds = 12345;
1120 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1121 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1122 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1123 EXPECT_LENW; EXPECT_EQW;
1125 /* Limit tests */
1127 curtime.wYear = 1601;
1128 curtime.wMonth = 1;
1129 curtime.wDay = 1;
1130 curtime.wDayOfWeek = 0; /* Irrelevant */
1131 curtime.wHour = 0;
1132 curtime.wMinute = 0;
1133 curtime.wSecond = 0;
1134 curtime.wMilliseconds = 0;
1135 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1136 SetLastError(0xdeadbeef);
1137 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1138 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1139 EXPECT_LENW; EXPECT_EQW;
1141 curtime.wYear = 1600;
1142 curtime.wMonth = 12;
1143 curtime.wDay = 31;
1144 curtime.wDayOfWeek = 0; /* Irrelevant */
1145 curtime.wHour = 23;
1146 curtime.wMinute = 59;
1147 curtime.wSecond = 59;
1148 curtime.wMilliseconds = 999;
1149 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1150 SetLastError(0xdeadbeef);
1151 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1152 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1153 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1157 #define CY_POS_LEFT 0
1158 #define CY_POS_RIGHT 1
1159 #define CY_POS_LEFT_SPACE 2
1160 #define CY_POS_RIGHT_SPACE 3
1162 static void test_GetCurrencyFormatA(void)
1164 static char szDot[] = { '.', '\0' };
1165 static char szComma[] = { ',', '\0' };
1166 static char szDollar[] = { '$', '\0' };
1167 int ret;
1168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1169 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1170 CURRENCYFMTA format;
1172 memset(&format, 0, sizeof(format));
1174 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1175 SetLastError(0xdeadbeef);
1176 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1177 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1178 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1180 STRINGSA("23,53",""); /* Invalid character --> Error */
1181 SetLastError(0xdeadbeef);
1182 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1183 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1184 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1186 STRINGSA("--",""); /* Double '-' --> Error */
1187 SetLastError(0xdeadbeef);
1188 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1189 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1190 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1192 STRINGSA("0-",""); /* Trailing '-' --> Error */
1193 SetLastError(0xdeadbeef);
1194 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1195 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1196 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1198 STRINGSA("0..",""); /* Double '.' --> Error */
1199 SetLastError(0xdeadbeef);
1200 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1201 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1202 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1204 STRINGSA(" 0.1",""); /* Leading space --> Error */
1205 SetLastError(0xdeadbeef);
1206 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1207 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1208 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1210 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1211 SetLastError(0xdeadbeef);
1212 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1213 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1214 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1216 STRINGSA("2353",""); /* Format and flags given --> Error */
1217 SetLastError(0xdeadbeef);
1218 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1219 ok( !ret, "Expected ret == 0, got %d\n", ret);
1220 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1221 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1223 STRINGSA("2353",""); /* Invalid format --> Error */
1224 SetLastError(0xdeadbeef);
1225 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1226 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1227 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1229 STRINGSA("2353","$2,353.00"); /* Valid number */
1230 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1231 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1232 EXPECT_LENA; EXPECT_EQA;
1234 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1235 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1237 EXPECT_LENA; EXPECT_EQA;
1239 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1240 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1241 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1242 EXPECT_LENA; EXPECT_EQA;
1244 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1245 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1246 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1247 EXPECT_LENA; EXPECT_EQA;
1249 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1250 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1251 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1252 EXPECT_LENA; EXPECT_EQA;
1254 format.NumDigits = 0; /* No decimal separator */
1255 format.LeadingZero = 0;
1256 format.Grouping = 0; /* No grouping char */
1257 format.NegativeOrder = 0;
1258 format.PositiveOrder = CY_POS_LEFT;
1259 format.lpDecimalSep = szDot;
1260 format.lpThousandSep = szComma;
1261 format.lpCurrencySymbol = szDollar;
1263 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1264 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1265 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1266 EXPECT_LENA; EXPECT_EQA;
1268 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1269 STRINGSA("2353","$2353.0");
1270 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1271 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1272 EXPECT_LENA; EXPECT_EQA;
1274 format.Grouping = 2; /* Group by 100's */
1275 STRINGSA("2353","$23,53.0");
1276 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1277 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1278 EXPECT_LENA; EXPECT_EQA;
1280 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1281 format.Grouping = 3;
1282 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1283 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1284 EXPECT_LENA; EXPECT_EQA;
1286 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1287 format.NegativeOrder = 2;
1288 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1289 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1290 EXPECT_LENA; EXPECT_EQA;
1292 format.LeadingZero = 1; /* Always provide leading zero */
1293 STRINGSA(".5","$0.5");
1294 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1295 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1296 EXPECT_LENA; EXPECT_EQA;
1298 format.PositiveOrder = CY_POS_RIGHT;
1299 STRINGSA("1","1.0$");
1300 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1301 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1302 EXPECT_LENA; EXPECT_EQA;
1304 format.PositiveOrder = CY_POS_LEFT_SPACE;
1305 STRINGSA("1","$ 1.0");
1306 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1307 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1308 EXPECT_LENA; EXPECT_EQA;
1310 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1311 STRINGSA("1","1.0 $");
1312 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1313 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1314 EXPECT_LENA; EXPECT_EQA;
1316 format.NegativeOrder = 0;
1317 STRINGSA("-1","($1.0)");
1318 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1319 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1320 EXPECT_LENA; EXPECT_EQA;
1322 format.NegativeOrder = 1;
1323 STRINGSA("-1","-$1.0");
1324 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1326 EXPECT_LENA; EXPECT_EQA;
1328 format.NegativeOrder = 2;
1329 STRINGSA("-1","$-1.0");
1330 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1331 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1332 EXPECT_LENA; EXPECT_EQA;
1334 format.NegativeOrder = 3;
1335 STRINGSA("-1","$1.0-");
1336 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1337 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1338 EXPECT_LENA; EXPECT_EQA;
1340 format.NegativeOrder = 4;
1341 STRINGSA("-1","(1.0$)");
1342 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1343 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1344 EXPECT_LENA; EXPECT_EQA;
1346 format.NegativeOrder = 5;
1347 STRINGSA("-1","-1.0$");
1348 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1349 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1350 EXPECT_LENA; EXPECT_EQA;
1352 format.NegativeOrder = 6;
1353 STRINGSA("-1","1.0-$");
1354 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1355 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1356 EXPECT_LENA; EXPECT_EQA;
1358 format.NegativeOrder = 7;
1359 STRINGSA("-1","1.0$-");
1360 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1361 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1362 EXPECT_LENA; EXPECT_EQA;
1364 format.NegativeOrder = 8;
1365 STRINGSA("-1","-1.0 $");
1366 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1368 EXPECT_LENA; EXPECT_EQA;
1370 format.NegativeOrder = 9;
1371 STRINGSA("-1","-$ 1.0");
1372 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1373 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1374 EXPECT_LENA; EXPECT_EQA;
1376 format.NegativeOrder = 10;
1377 STRINGSA("-1","1.0 $-");
1378 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1379 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1380 EXPECT_LENA; EXPECT_EQA;
1382 format.NegativeOrder = 11;
1383 STRINGSA("-1","$ 1.0-");
1384 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1385 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1386 EXPECT_LENA; EXPECT_EQA;
1388 format.NegativeOrder = 12;
1389 STRINGSA("-1","$ -1.0");
1390 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1391 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1392 EXPECT_LENA; EXPECT_EQA;
1394 format.NegativeOrder = 13;
1395 STRINGSA("-1","1.0- $");
1396 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1397 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1398 EXPECT_LENA; EXPECT_EQA;
1400 format.NegativeOrder = 14;
1401 STRINGSA("-1","($ 1.0)");
1402 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1403 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1404 EXPECT_LENA; EXPECT_EQA;
1406 format.NegativeOrder = 15;
1407 STRINGSA("-1","(1.0 $)");
1408 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1409 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1410 EXPECT_LENA; EXPECT_EQA;
1413 #define NEG_PARENS 0 /* "(1.1)" */
1414 #define NEG_LEFT 1 /* "-1.1" */
1415 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1416 #define NEG_RIGHT 3 /* "1.1-" */
1417 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1419 static void test_GetNumberFormatA(void)
1421 static char szDot[] = { '.', '\0' };
1422 static char szComma[] = { ',', '\0' };
1423 int ret;
1424 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1425 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1426 NUMBERFMTA format;
1428 memset(&format, 0, sizeof(format));
1430 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1431 SetLastError(0xdeadbeef);
1432 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1433 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1434 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1436 STRINGSA("23,53",""); /* Invalid character --> Error */
1437 SetLastError(0xdeadbeef);
1438 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1442 STRINGSA("--",""); /* Double '-' --> Error */
1443 SetLastError(0xdeadbeef);
1444 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1445 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1448 STRINGSA("0-",""); /* Trailing '-' --> Error */
1449 SetLastError(0xdeadbeef);
1450 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1451 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1452 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1454 STRINGSA("0..",""); /* Double '.' --> Error */
1455 SetLastError(0xdeadbeef);
1456 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1457 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1458 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1460 STRINGSA(" 0.1",""); /* Leading space --> Error */
1461 SetLastError(0xdeadbeef);
1462 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1463 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1464 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1466 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1467 SetLastError(0xdeadbeef);
1468 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1469 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1470 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1472 STRINGSA("2353",""); /* Format and flags given --> Error */
1473 SetLastError(0xdeadbeef);
1474 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1475 ok( !ret, "Expected ret == 0, got %d\n", ret);
1476 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1477 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1479 STRINGSA("2353",""); /* Invalid format --> Error */
1480 SetLastError(0xdeadbeef);
1481 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1482 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1483 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1485 STRINGSA("2353","2,353.00"); /* Valid number */
1486 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1488 EXPECT_LENA; EXPECT_EQA;
1490 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1491 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1493 EXPECT_LENA; EXPECT_EQA;
1495 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1496 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1498 EXPECT_LENA; EXPECT_EQA;
1500 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1501 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1503 EXPECT_LENA; EXPECT_EQA;
1505 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1506 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1507 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1508 EXPECT_LENA; EXPECT_EQA;
1510 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1511 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1512 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1513 EXPECT_LENA; EXPECT_EQA;
1515 format.NumDigits = 0; /* No decimal separator */
1516 format.LeadingZero = 0;
1517 format.Grouping = 0; /* No grouping char */
1518 format.NegativeOrder = 0;
1519 format.lpDecimalSep = szDot;
1520 format.lpThousandSep = szComma;
1522 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1523 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1525 EXPECT_LENA; EXPECT_EQA;
1527 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1528 STRINGSA("2353","2353.0");
1529 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1531 EXPECT_LENA; EXPECT_EQA;
1533 format.Grouping = 2; /* Group by 100's */
1534 STRINGSA("2353","23,53.0");
1535 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1536 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1537 EXPECT_LENA; EXPECT_EQA;
1539 STRINGSA("235","235.0"); /* Grouping of a positive number */
1540 format.Grouping = 3;
1541 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1543 EXPECT_LENA; EXPECT_EQA;
1545 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1546 format.NegativeOrder = NEG_LEFT;
1547 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1548 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1549 EXPECT_LENA; EXPECT_EQA;
1551 format.LeadingZero = 1; /* Always provide leading zero */
1552 STRINGSA(".5","0.5");
1553 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1554 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1555 EXPECT_LENA; EXPECT_EQA;
1557 format.NegativeOrder = NEG_PARENS;
1558 STRINGSA("-1","(1.0)");
1559 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1561 EXPECT_LENA; EXPECT_EQA;
1563 format.NegativeOrder = NEG_LEFT;
1564 STRINGSA("-1","-1.0");
1565 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1567 EXPECT_LENA; EXPECT_EQA;
1569 format.NegativeOrder = NEG_LEFT_SPACE;
1570 STRINGSA("-1","- 1.0");
1571 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1573 EXPECT_LENA; EXPECT_EQA;
1575 format.NegativeOrder = NEG_RIGHT;
1576 STRINGSA("-1","1.0-");
1577 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1579 EXPECT_LENA; EXPECT_EQA;
1581 format.NegativeOrder = NEG_RIGHT_SPACE;
1582 STRINGSA("-1","1.0 -");
1583 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1585 EXPECT_LENA; EXPECT_EQA;
1587 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1589 if (IsValidLocale(lcid, 0))
1591 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1592 Expected[3] = 160; /* Non breaking space */
1593 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1595 EXPECT_LENA; EXPECT_EQA;
1599 static void test_GetNumberFormatEx(void)
1601 int ret;
1602 NUMBERFMTW format;
1603 static WCHAR dotW[] = {'.',0};
1604 static WCHAR commaW[] = {',',0};
1605 static const WCHAR enW[] = {'e','n','-','U','S',0};
1606 static const WCHAR frW[] = {'f','r','-','F','R',0};
1607 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1608 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1610 if (!pGetNumberFormatEx)
1612 win_skip("GetNumberFormatEx is not available.\n");
1613 return;
1616 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1617 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1618 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1619 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1621 STRINGSW("23,53",""); /* Invalid character --> Error */
1622 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1623 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1624 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1626 STRINGSW("--",""); /* Double '-' --> Error */
1627 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1628 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1629 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1631 STRINGSW("0-",""); /* Trailing '-' --> Error */
1632 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1633 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1634 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1636 STRINGSW("0..",""); /* Double '.' --> Error */
1637 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1638 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1639 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1641 STRINGSW(" 0.1",""); /* Leading space --> Error */
1642 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1643 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1644 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1646 STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1647 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1648 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1649 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1651 STRINGSW("23",""); /* Bogus locale --> Error */
1652 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1653 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1654 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1656 memset(&format, 0, sizeof(format));
1658 STRINGSW("2353",""); /* Format and flags given --> Error */
1659 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1660 ok( !ret, "Expected ret == 0, got %d\n", ret);
1661 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1662 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1664 STRINGSW("2353",""); /* Invalid format --> Error */
1665 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1666 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1667 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1669 STRINGSW("2353","2,353.00"); /* Valid number */
1670 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1672 EXPECT_LENW; EXPECT_EQW;
1674 STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1675 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1676 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1677 EXPECT_LENW; EXPECT_EQW;
1679 STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1680 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1682 EXPECT_LENW; EXPECT_EQW;
1684 STRINGSW("2353.1","2,353.10"); /* Valid real number */
1685 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1686 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1687 EXPECT_LENW; EXPECT_EQW;
1689 STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1690 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1691 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1692 EXPECT_LENW; EXPECT_EQW;
1694 STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */
1695 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1696 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1697 EXPECT_LENW; EXPECT_EQW;
1699 format.NumDigits = 0; /* No decimal separator */
1700 format.LeadingZero = 0;
1701 format.Grouping = 0; /* No grouping char */
1702 format.NegativeOrder = 0;
1703 format.lpDecimalSep = dotW;
1704 format.lpThousandSep = commaW;
1706 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1707 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1708 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1709 EXPECT_LENW; EXPECT_EQW;
1711 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1712 STRINGSW("2353","2353.0");
1713 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1715 EXPECT_LENW; EXPECT_EQW;
1717 format.Grouping = 2; /* Group by 100's */
1718 STRINGSW("2353","23,53.0");
1719 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1720 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1721 EXPECT_LENW; EXPECT_EQW;
1723 STRINGSW("235","235.0"); /* Grouping of a positive number */
1724 format.Grouping = 3;
1725 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1726 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1727 EXPECT_LENW; EXPECT_EQW;
1729 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1730 format.NegativeOrder = NEG_LEFT;
1731 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1732 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1733 EXPECT_LENW; EXPECT_EQW;
1735 format.LeadingZero = 1; /* Always provide leading zero */
1736 STRINGSW(".5","0.5");
1737 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1738 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1739 EXPECT_LENW; EXPECT_EQW;
1741 format.NegativeOrder = NEG_PARENS;
1742 STRINGSW("-1","(1.0)");
1743 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1744 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1745 EXPECT_LENW; EXPECT_EQW;
1747 format.NegativeOrder = NEG_LEFT;
1748 STRINGSW("-1","-1.0");
1749 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1750 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1751 EXPECT_LENW; EXPECT_EQW;
1753 format.NegativeOrder = NEG_LEFT_SPACE;
1754 STRINGSW("-1","- 1.0");
1755 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1757 EXPECT_LENW; EXPECT_EQW;
1759 format.NegativeOrder = NEG_RIGHT;
1760 STRINGSW("-1","1.0-");
1761 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1762 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1763 EXPECT_LENW; EXPECT_EQW;
1765 format.NegativeOrder = NEG_RIGHT_SPACE;
1766 STRINGSW("-1","1.0 -");
1767 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1768 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1769 EXPECT_LENW; EXPECT_EQW;
1771 if (pIsValidLocaleName(frW))
1773 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1774 Expected[3] = 160; /* Non breaking space */
1775 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1776 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1777 EXPECT_LENW; EXPECT_EQW;
1781 struct comparestringa_entry {
1782 LCID lcid;
1783 DWORD flags;
1784 const char *first;
1785 int first_len;
1786 const char *second;
1787 int second_len;
1788 int ret;
1791 static const struct comparestringa_entry comparestringa_data[] = {
1792 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1793 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1794 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_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, "Aab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1808 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1809 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1810 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1811 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1812 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1813 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1814 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1818 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1820 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1821 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1823 { LOCALE_SYSTEM_DEFAULT, 0, "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, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1826 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1827 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1828 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1833 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1834 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1835 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1838 static void test_CompareStringA(void)
1840 int ret, i;
1841 char a[256];
1842 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1844 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1846 const struct comparestringa_entry *entry = &comparestringa_data[i];
1848 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1849 entry->second, entry->second_len);
1850 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1853 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1854 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1856 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1857 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1859 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1860 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1862 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1863 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1865 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1867 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1868 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1870 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1871 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1873 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1874 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1876 /* test for CompareStringA flags */
1877 SetLastError(0xdeadbeef);
1878 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1879 ok(GetLastError() == ERROR_INVALID_FLAGS,
1880 "unexpected error code %d\n", GetLastError());
1881 ok(!ret, "CompareStringA must fail with invalid flag\n");
1883 SetLastError(0xdeadbeef);
1884 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1885 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1886 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1887 /* end of test for CompareStringA flags */
1889 ret = lstrcmpA("", "");
1890 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1892 ret = lstrcmpA(NULL, NULL);
1893 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1895 ret = lstrcmpA("", NULL);
1896 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1898 ret = lstrcmpA(NULL, "");
1899 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1902 if (0) { /* this requires collation table patch to make it MS compatible */
1903 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1904 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1906 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1907 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1909 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1910 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1912 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1913 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1915 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1916 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1918 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1919 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1921 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1922 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1924 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1925 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1927 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1928 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1930 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1931 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1933 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1934 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1936 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1937 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1941 /* WinXP handles embedded NULLs differently than earlier versions */
1942 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1943 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1945 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1946 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);
1948 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1949 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1951 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1952 ok(ret == CSTR_EQUAL || /* win2k */
1953 ret == CSTR_GREATER_THAN,
1954 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1956 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1957 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1959 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1960 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1962 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1963 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1965 ret = lstrcmpiA("#", ".");
1966 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1968 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1970 /* \xB9 character lies between a and b */
1971 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1972 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1973 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1974 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1976 memset(a, 'a', sizeof(a));
1977 SetLastError(0xdeadbeef);
1978 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1979 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1980 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1983 static void test_CompareStringW(void)
1985 WCHAR *str1, *str2;
1986 SYSTEM_INFO si;
1987 DWORD old_prot;
1988 BOOL success;
1989 char *buf;
1990 int ret;
1992 GetSystemInfo(&si);
1993 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1994 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1995 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1996 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1997 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1998 ok(success, "VirtualProtect failed with %u\n", GetLastError());
2000 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2001 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2002 *str1 = 'A';
2003 *str2 = 'B';
2005 /* CompareStringW should abort on the first non-matching character */
2006 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2007 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2009 success = VirtualFree(buf, 0, MEM_RELEASE);
2010 ok(success, "VirtualFree failed with %u\n", GetLastError());
2013 struct comparestringex_test {
2014 const char *locale;
2015 DWORD flags;
2016 const WCHAR first[2];
2017 const WCHAR second[2];
2018 INT ret;
2019 INT broken;
2020 BOOL todo;
2023 static const struct comparestringex_test comparestringex_tests[] = {
2024 /* default behavior */
2025 { /* 0 */
2026 "tr-TR", 0,
2027 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2029 { /* 1 */
2030 "tr-TR", 0,
2031 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2033 { /* 2 */
2034 "tr-TR", 0,
2035 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2037 { /* 3 */
2038 "tr-TR", 0,
2039 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2041 { /* 4 */
2042 "tr-TR", 0,
2043 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2045 { /* 5 */
2046 "tr-TR", 0,
2047 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2049 /* with NORM_IGNORECASE */
2050 { /* 6 */
2051 "tr-TR", NORM_IGNORECASE,
2052 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2054 { /* 7 */
2055 "tr-TR", NORM_IGNORECASE,
2056 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2058 { /* 8 */
2059 "tr-TR", NORM_IGNORECASE,
2060 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2062 { /* 9 */
2063 "tr-TR", NORM_IGNORECASE,
2064 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2066 { /* 10 */
2067 "tr-TR", NORM_IGNORECASE,
2068 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2070 { /* 11 */
2071 "tr-TR", NORM_IGNORECASE,
2072 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2074 /* with NORM_LINGUISTIC_CASING */
2075 { /* 12 */
2076 "tr-TR", NORM_LINGUISTIC_CASING,
2077 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2079 { /* 13 */
2080 "tr-TR", NORM_LINGUISTIC_CASING,
2081 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2083 { /* 14 */
2084 "tr-TR", NORM_LINGUISTIC_CASING,
2085 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2087 { /* 15 */
2088 "tr-TR", NORM_LINGUISTIC_CASING,
2089 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2091 { /* 16 */
2092 "tr-TR", NORM_LINGUISTIC_CASING,
2093 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2095 { /* 17 */
2096 "tr-TR", NORM_LINGUISTIC_CASING,
2097 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2099 /* with LINGUISTIC_IGNORECASE */
2100 { /* 18 */
2101 "tr-TR", LINGUISTIC_IGNORECASE,
2102 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2104 { /* 19 */
2105 "tr-TR", LINGUISTIC_IGNORECASE,
2106 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2108 { /* 20 */
2109 "tr-TR", LINGUISTIC_IGNORECASE,
2110 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2112 { /* 21 */
2113 "tr-TR", LINGUISTIC_IGNORECASE,
2114 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2116 { /* 22 */
2117 "tr-TR", LINGUISTIC_IGNORECASE,
2118 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2120 { /* 23 */
2121 "tr-TR", LINGUISTIC_IGNORECASE,
2122 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2124 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2125 { /* 24 */
2126 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2127 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2129 { /* 25 */
2130 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2131 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2133 { /* 26 */
2134 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2135 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2137 { /* 27 */
2138 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2139 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2141 { /* 28 */
2142 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2143 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2145 { /* 29 */
2146 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2147 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2149 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2150 { /* 30 */
2151 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2152 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2154 { /* 31 */
2155 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2156 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2158 { /* 32 */
2159 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2160 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2162 { /* 33 */
2163 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2164 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2166 { /* 34 */
2167 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2168 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2170 { /* 35 */
2171 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2172 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2176 static void test_CompareStringEx(void)
2178 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2179 WCHAR locale[6];
2180 INT ret, i;
2182 /* CompareStringEx is only available on Vista+ */
2183 if (!pCompareStringEx)
2185 win_skip("CompareStringEx not supported\n");
2186 return;
2189 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2191 const struct comparestringex_test *e = &comparestringex_tests[i];
2193 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2194 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2195 todo_wine_if (e->todo)
2196 ok(ret == e->ret || broken(ret == e->broken),
2197 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2202 static const DWORD lcmap_invalid_flags[] = {
2204 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2205 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2206 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2207 LCMAP_LOWERCASE | SORT_STRINGSORT,
2208 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2209 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2210 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2211 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2212 LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2213 LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2214 LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2215 LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2216 LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2217 LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2218 LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2219 LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2220 LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2221 LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2222 LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2223 LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2224 LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2225 LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2226 LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2227 LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2230 static void test_LCMapStringA(void)
2232 int ret, ret2, i;
2233 char buf[256], buf2[256];
2234 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2235 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2236 static const char symbols_stripped[] = "justateststring1";
2238 SetLastError(0xdeadbeef);
2239 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2240 lower_case, -1, buf, sizeof(buf));
2241 ok(ret == lstrlenA(lower_case) + 1,
2242 "ret %d, error %d, expected value %d\n",
2243 ret, GetLastError(), lstrlenA(lower_case) + 1);
2244 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2246 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2247 upper_case, -1, buf, sizeof(buf));
2248 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2249 ok(GetLastError() == ERROR_INVALID_FLAGS,
2250 "unexpected error code %d\n", GetLastError());
2252 /* test invalid flag combinations */
2253 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2254 lstrcpyA(buf, "foo");
2255 SetLastError(0xdeadbeef);
2256 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2257 lower_case, -1, buf, sizeof(buf));
2258 ok(GetLastError() == ERROR_INVALID_FLAGS,
2259 "LCMapStringA (flag %08x) unexpected error code %d\n",
2260 lcmap_invalid_flags[i], GetLastError());
2261 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2262 lcmap_invalid_flags[i], ret);
2265 /* test LCMAP_LOWERCASE */
2266 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2267 upper_case, -1, buf, sizeof(buf));
2268 ok(ret == lstrlenA(upper_case) + 1,
2269 "ret %d, error %d, expected value %d\n",
2270 ret, GetLastError(), lstrlenA(upper_case) + 1);
2271 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2273 /* test LCMAP_UPPERCASE */
2274 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2275 lower_case, -1, buf, sizeof(buf));
2276 ok(ret == lstrlenA(lower_case) + 1,
2277 "ret %d, error %d, expected value %d\n",
2278 ret, GetLastError(), lstrlenA(lower_case) + 1);
2279 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2281 /* test buffer overflow */
2282 SetLastError(0xdeadbeef);
2283 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2284 lower_case, -1, buf, 4);
2285 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2286 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2288 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2289 lstrcpyA(buf, lower_case);
2290 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2291 buf, -1, buf, sizeof(buf));
2292 if (!ret) /* Win9x */
2293 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2294 else
2296 ok(ret == lstrlenA(lower_case) + 1,
2297 "ret %d, error %d, expected value %d\n",
2298 ret, GetLastError(), lstrlenA(lower_case) + 1);
2299 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2301 lstrcpyA(buf, upper_case);
2302 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2303 buf, -1, buf, sizeof(buf));
2304 if (!ret) /* Win9x */
2305 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2306 else
2308 ok(ret == lstrlenA(upper_case) + 1,
2309 "ret %d, error %d, expected value %d\n",
2310 ret, GetLastError(), lstrlenA(lower_case) + 1);
2311 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2314 /* otherwise src == dst should fail */
2315 SetLastError(0xdeadbeef);
2316 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2317 buf, 10, buf, sizeof(buf));
2318 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2319 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2320 "unexpected error code %d\n", GetLastError());
2321 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2323 /* test whether '\0' is always appended */
2324 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2325 upper_case, -1, buf, sizeof(buf));
2326 ok(ret, "LCMapStringA must succeed\n");
2327 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2328 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2329 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2330 ok(ret2, "LCMapStringA must succeed\n");
2331 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2332 ok(ret == ret2, "lengths of sort keys must be equal\n");
2333 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2335 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2336 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2337 upper_case, -1, buf, sizeof(buf));
2338 ok(ret, "LCMapStringA must succeed\n");
2339 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2340 lower_case, -1, buf2, sizeof(buf2));
2341 ok(ret2, "LCMapStringA must succeed\n");
2342 ok(ret == ret2, "lengths of sort keys must be equal\n");
2343 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2345 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2346 results from plain LCMAP_SORTKEY on Vista */
2348 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2349 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2350 lower_case, -1, buf, sizeof(buf));
2351 ok(ret, "LCMapStringA must succeed\n");
2352 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2353 symbols_stripped, -1, buf2, sizeof(buf2));
2354 ok(ret2, "LCMapStringA must succeed\n");
2355 ok(ret == ret2, "lengths of sort keys must be equal\n");
2356 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2358 /* test NORM_IGNORENONSPACE */
2359 lstrcpyA(buf, "foo");
2360 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2361 lower_case, -1, buf, sizeof(buf));
2362 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2363 lstrlenA(lower_case) + 1, ret);
2364 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2366 /* test NORM_IGNORESYMBOLS */
2367 lstrcpyA(buf, "foo");
2368 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2369 lower_case, -1, buf, sizeof(buf));
2370 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2371 lstrlenA(symbols_stripped) + 1, ret);
2372 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2374 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2375 lstrcpyA(buf, "foo");
2376 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2377 lower_case, -1, buf, sizeof(buf));
2378 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2379 lstrlenA(symbols_stripped) + 1, ret);
2380 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2382 /* test srclen = 0 */
2383 SetLastError(0xdeadbeef);
2384 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2385 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2386 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2387 "unexpected error code %d\n", GetLastError());
2390 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2392 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2394 const static WCHAR japanese_text[] = {
2395 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2396 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2398 const static WCHAR hiragana_text[] = {
2399 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2400 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2402 const static WCHAR katakana_text[] = {
2403 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2404 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2406 const static WCHAR halfwidth_text[] = {
2407 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2408 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2410 int ret, ret2, i;
2411 WCHAR buf[256], buf2[256];
2412 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2414 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2415 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2416 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2417 todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2418 "%s ret %d, error %d, expected value %d\n", func_name,
2419 ret, GetLastError(), lstrlenW(title_case) + 1);
2420 todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2421 "Expected title case string\n");
2423 /* test invalid flag combinations */
2424 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2425 lstrcpyW(buf, fooW);
2426 SetLastError(0xdeadbeef);
2427 ret = func_ptr(lcmap_invalid_flags[i],
2428 lower_case, -1, buf, sizeof(buf));
2429 ok(GetLastError() == ERROR_INVALID_FLAGS,
2430 "%s (flag %08x) unexpected error code %d\n",
2431 func_name, lcmap_invalid_flags[i], GetLastError());
2432 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2433 func_name, lcmap_invalid_flags[i], ret);
2436 /* test LCMAP_LOWERCASE */
2437 ret = func_ptr(LCMAP_LOWERCASE,
2438 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2439 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2440 ret, GetLastError(), lstrlenW(upper_case) + 1);
2441 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2443 /* test LCMAP_UPPERCASE */
2444 ret = func_ptr(LCMAP_UPPERCASE,
2445 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2446 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2447 ret, GetLastError(), lstrlenW(lower_case) + 1);
2448 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2450 /* test LCMAP_HIRAGANA */
2451 ret = func_ptr(LCMAP_HIRAGANA,
2452 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2453 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2454 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2455 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2457 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2458 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2459 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2460 ret, GetLastError());
2461 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2462 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2463 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2465 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2466 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
2467 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2468 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2469 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2470 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2472 /* test LCMAP_FULLWIDTH */
2473 ret = func_ptr(LCMAP_FULLWIDTH,
2474 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2475 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2476 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2477 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2479 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2480 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2482 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2483 (half-width katakana is converted into full-wdith hiragana) */
2484 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
2485 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2486 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2487 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2488 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2490 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2491 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2493 /* test LCMAP_HALFWIDTH */
2494 ret = func_ptr(LCMAP_HALFWIDTH,
2495 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2496 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2497 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2498 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2500 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2501 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2503 /* test buffer overflow */
2504 SetLastError(0xdeadbeef);
2505 ret = func_ptr(LCMAP_UPPERCASE,
2506 lower_case, -1, buf, 4);
2507 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2508 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2510 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2511 Thus, it requires two WCHARs. */
2512 buf[0] = 0x30ac;
2513 SetLastError(0xdeadbeef);
2514 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2515 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2516 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2518 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2519 lstrcpyW(buf, lower_case);
2520 ret = func_ptr(LCMAP_UPPERCASE,
2521 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2522 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2523 ret, GetLastError(), lstrlenW(lower_case) + 1);
2524 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2526 lstrcpyW(buf, upper_case);
2527 ret = func_ptr(LCMAP_LOWERCASE,
2528 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2529 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2530 ret, GetLastError(), lstrlenW(lower_case) + 1);
2531 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2533 /* otherwise src == dst should fail */
2534 SetLastError(0xdeadbeef);
2535 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2536 buf, 10, buf, sizeof(buf));
2537 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2538 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2539 "%s unexpected error code %d\n", func_name, GetLastError());
2540 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2542 /* test whether '\0' is always appended */
2543 ret = func_ptr(LCMAP_SORTKEY,
2544 upper_case, -1, buf, sizeof(buf));
2545 ok(ret, "%s func_ptr must succeed\n", func_name);
2546 ret2 = func_ptr(LCMAP_SORTKEY,
2547 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2548 ok(ret, "%s func_ptr must succeed\n", func_name);
2549 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2550 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2552 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2553 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2554 upper_case, -1, buf, sizeof(buf));
2555 ok(ret, "%s func_ptr must succeed\n", func_name);
2556 ret2 = func_ptr(LCMAP_SORTKEY,
2557 lower_case, -1, buf2, sizeof(buf2));
2558 ok(ret2, "%s func_ptr must succeed\n", func_name);
2559 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2560 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2562 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2563 results from plain LCMAP_SORTKEY on Vista */
2565 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2566 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2567 lower_case, -1, buf, sizeof(buf));
2568 ok(ret, "%s func_ptr must succeed\n", func_name);
2569 ret2 = func_ptr(LCMAP_SORTKEY,
2570 symbols_stripped, -1, buf2, sizeof(buf2));
2571 ok(ret2, "%s func_ptr must succeed\n", func_name);
2572 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2573 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2575 /* test NORM_IGNORENONSPACE */
2576 lstrcpyW(buf, fooW);
2577 ret = func_ptr(NORM_IGNORENONSPACE,
2578 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2579 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2580 lstrlenW(lower_case) + 1, ret);
2581 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2583 /* test NORM_IGNORESYMBOLS */
2584 lstrcpyW(buf, fooW);
2585 ret = func_ptr(NORM_IGNORESYMBOLS,
2586 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2587 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2588 lstrlenW(symbols_stripped) + 1, ret);
2589 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2591 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2592 lstrcpyW(buf, fooW);
2593 ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2594 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2595 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2596 lstrlenW(symbols_stripped) + 1, ret);
2597 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2599 /* test srclen = 0 */
2600 SetLastError(0xdeadbeef);
2601 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2602 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2603 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2604 "%s unexpected error code %d\n", func_name, GetLastError());
2607 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2609 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2612 static void test_LCMapStringW(void)
2614 int ret;
2615 WCHAR buf[256];
2617 trace("testing LCMapStringW\n");
2619 SetLastError(0xdeadbeef);
2620 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2621 todo_wine {
2622 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2623 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2626 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2629 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2631 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2634 static void test_LCMapStringEx(void)
2636 int ret;
2637 WCHAR buf[256];
2639 if (!pLCMapStringEx)
2641 win_skip( "LCMapStringEx not available\n" );
2642 return;
2645 trace("testing LCMapStringEx\n");
2647 SetLastError(0xdeadbeef);
2648 ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2649 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2650 todo_wine {
2651 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2652 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2655 /* test reserved parameters */
2656 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2657 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2658 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2659 ret, GetLastError(), lstrlenW(upper_case) + 1);
2660 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2662 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2663 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2664 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2665 ret, GetLastError(), lstrlenW(upper_case) + 1);
2666 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2668 /* crashes on native */
2669 if(0)
2670 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2671 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2673 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2676 struct neutralsublang_name_t {
2677 WCHAR name[3];
2678 WCHAR sname[16];
2679 LCID lcid;
2680 int todo;
2683 static const struct neutralsublang_name_t neutralsublang_names[] = {
2684 { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2685 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2686 { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2687 { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2688 { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2689 { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2690 { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2691 { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2692 { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2693 { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2694 { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2695 { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2696 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2697 { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2698 { {0} }
2701 static void test_LocaleNameToLCID(void)
2703 LCID lcid;
2704 INT ret;
2705 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2706 static const WCHAR enW[] = {'e','n',0};
2707 static const WCHAR esesW[] = {'e','s','-','e','s',0};
2708 static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
2709 static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
2710 static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
2711 static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
2712 static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
2713 static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
2715 if (!pLocaleNameToLCID)
2717 win_skip( "LocaleNameToLCID not available\n" );
2718 return;
2721 /* special cases */
2722 buffer[0] = 0;
2723 SetLastError(0xdeadbeef);
2724 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2725 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2726 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), 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_SYSTEM_DEFAULT, 0);
2734 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2735 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2736 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2737 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2738 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2740 buffer[0] = 0;
2741 SetLastError(0xdeadbeef);
2742 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2743 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2744 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2745 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2746 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2748 /* bad name */
2749 SetLastError(0xdeadbeef);
2750 lcid = pLocaleNameToLCID(invalidW, 0);
2751 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2752 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2754 /* lower-case */
2755 lcid = pLocaleNameToLCID(esesW, 0);
2756 ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid);
2758 /* english neutral name */
2759 lcid = pLocaleNameToLCID(enW, 0);
2760 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2761 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2762 if (lcid)
2764 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2766 while (*ptr->name)
2768 lcid = pLocaleNameToLCID(ptr->name, 0);
2769 todo_wine_if (ptr->todo)
2770 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2771 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2773 *buffer = 0;
2774 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2775 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2776 ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
2777 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2779 ptr++;
2782 /* zh-Hant */
2783 lcid = pLocaleNameToLCID(zhHantW, 0);
2784 todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2785 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid);
2786 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2787 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2788 todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2789 wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2791 /* zh-hant */
2792 lcid = pLocaleNameToLCID(zhhantW, 0);
2793 todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2794 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW),
2795 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT));
2796 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2797 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret);
2798 todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2799 wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer));
2801 /* zh-Hans */
2802 lcid = pLocaleNameToLCID(zhHansW, 0);
2803 todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2804 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid);
2805 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2806 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2807 todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2808 wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2810 /* zh-hans */
2811 lcid = pLocaleNameToLCID(zhhansW, 0);
2812 todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2813 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW),
2814 MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT));
2815 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2816 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret);
2817 todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2818 wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
2822 /* this requires collation table patch to make it MS compatible */
2823 static const char * const strings_sorted[] =
2825 "'",
2826 "-",
2827 "!",
2828 "\"",
2829 ".",
2830 ":",
2831 "\\",
2832 "_",
2833 "`",
2834 "{",
2835 "}",
2836 "+",
2837 "0",
2838 "1",
2839 "2",
2840 "3",
2841 "4",
2842 "5",
2843 "6",
2844 "7",
2845 "8",
2846 "9",
2847 "a",
2848 "A",
2849 "b",
2850 "B",
2851 "c",
2855 static const char * const strings[] =
2857 "C",
2858 "\"",
2859 "9",
2860 "'",
2861 "}",
2862 "-",
2863 "7",
2864 "+",
2865 "`",
2866 "1",
2867 "a",
2868 "5",
2869 "\\",
2870 "8",
2871 "B",
2872 "3",
2873 "_",
2874 "6",
2875 "{",
2876 "2",
2877 "c",
2878 "4",
2879 "!",
2880 "0",
2881 "A",
2882 ":",
2883 "b",
2887 static int compare_string1(const void *e1, const void *e2)
2889 const char *s1 = *(const char *const *)e1;
2890 const char *s2 = *(const char *const *)e2;
2892 return lstrcmpA(s1, s2);
2895 static int compare_string2(const void *e1, const void *e2)
2897 const char *s1 = *(const char *const *)e1;
2898 const char *s2 = *(const char *const *)e2;
2900 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2903 static int compare_string3(const void *e1, const void *e2)
2905 const char *s1 = *(const char *const *)e1;
2906 const char *s2 = *(const char *const *)e2;
2907 char key1[256], key2[256];
2909 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2910 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2911 return strcmp(key1, key2);
2914 static void test_sorting(void)
2916 char buf[256];
2917 char **str_buf = (char **)buf;
2918 int i;
2920 assert(sizeof(buf) >= sizeof(strings));
2922 /* 1. sort using lstrcmpA */
2923 memcpy(buf, strings, sizeof(strings));
2924 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2925 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2927 ok(!strcmp(strings_sorted[i], str_buf[i]),
2928 "qsort using lstrcmpA failed for element %d\n", i);
2930 /* 2. sort using CompareStringA */
2931 memcpy(buf, strings, sizeof(strings));
2932 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2933 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2935 ok(!strcmp(strings_sorted[i], str_buf[i]),
2936 "qsort using CompareStringA failed for element %d\n", i);
2938 /* 3. sort using sort keys */
2939 memcpy(buf, strings, sizeof(strings));
2940 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2941 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2943 ok(!strcmp(strings_sorted[i], str_buf[i]),
2944 "qsort using sort keys failed for element %d\n", i);
2948 static void test_FoldStringA(void)
2950 int ret, i, j;
2951 BOOL is_special;
2952 char src[256], dst[256];
2953 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2954 static const char digits_dst[] = { '1','2','3','\0' };
2955 static const char composite_src[] =
2957 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2958 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2959 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2960 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2961 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2962 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2963 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2964 0xfb,0xfc,0xfd,0xff,'\0'
2966 static const char composite_dst[] =
2968 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2969 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2970 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2971 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2972 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2973 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2974 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2975 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2976 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2977 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2978 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2979 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2980 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2981 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2982 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2984 static const char composite_dst_alt[] =
2986 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2987 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2988 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2989 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2990 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2991 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2992 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2993 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2994 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2995 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2996 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2997 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2998 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2999 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3000 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3002 static const char ligatures_src[] =
3004 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3006 static const char ligatures_dst[] =
3008 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3010 static const struct special
3012 char src;
3013 char dst[4];
3014 } foldczone_special[] =
3016 /* src dst */
3017 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3018 { 0x98, { 0x20, 0x7e, 0x00 } },
3019 { 0x99, { 0x54, 0x4d, 0x00 } },
3020 { 0xa0, { 0x20, 0x00 } },
3021 { 0xa8, { 0x20, 0xa8, 0x00 } },
3022 { 0xaa, { 0x61, 0x00 } },
3023 { 0xaf, { 0x20, 0xaf, 0x00 } },
3024 { 0xb2, { 0x32, 0x00 } },
3025 { 0xb3, { 0x33, 0x00 } },
3026 { 0xb4, { 0x20, 0xb4, 0x00 } },
3027 { 0xb8, { 0x20, 0xb8, 0x00 } },
3028 { 0xb9, { 0x31, 0x00 } },
3029 { 0xba, { 0x6f, 0x00 } },
3030 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3031 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
3032 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
3033 { 0x00 }
3036 if (!pFoldStringA)
3037 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3039 /* these tests are locale specific */
3040 if (GetACP() != 1252)
3042 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
3043 return;
3046 /* MAP_FOLDDIGITS */
3047 SetLastError(0);
3048 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
3049 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3051 win_skip("FoldStringA is not implemented\n");
3052 return;
3054 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
3055 ok(strcmp(dst, digits_dst) == 0,
3056 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
3057 for (i = 1; i < 256; i++)
3059 if (!strchr(digits_src, i))
3061 src[0] = i;
3062 src[1] = '\0';
3063 SetLastError(0);
3064 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
3065 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3066 ok(dst[0] == src[0],
3067 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3071 /* MAP_EXPAND_LIGATURES */
3072 SetLastError(0);
3073 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3074 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3075 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3076 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3077 ok(strcmp(dst, ligatures_dst) == 0,
3078 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3079 for (i = 1; i < 256; i++)
3081 if (!strchr(ligatures_src, i))
3083 src[0] = i;
3084 src[1] = '\0';
3085 SetLastError(0);
3086 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3087 if (ret == 3)
3089 /* Vista */
3090 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3091 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3092 "Got %s for %d\n", dst, i);
3094 else
3096 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3097 ok(dst[0] == src[0],
3098 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3104 /* MAP_COMPOSITE */
3105 SetLastError(0);
3106 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3107 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3108 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3109 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3110 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3112 for (i = 1; i < 256; i++)
3114 if (!strchr(composite_src, i))
3116 src[0] = i;
3117 src[1] = '\0';
3118 SetLastError(0);
3119 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3120 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3121 ok(dst[0] == src[0],
3122 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3123 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3127 /* MAP_FOLDCZONE */
3128 for (i = 1; i < 256; i++)
3130 src[0] = i;
3131 src[1] = '\0';
3132 SetLastError(0);
3133 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3134 is_special = FALSE;
3135 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3137 if (foldczone_special[j].src == src[0])
3139 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3140 "Expected ret == 2 or %d, got %d, error %d\n",
3141 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3142 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3143 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3144 (unsigned char)src[0]);
3145 is_special = TRUE;
3148 if (! is_special)
3150 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3151 ok(src[0] == dst[0],
3152 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3153 (unsigned char)src[0], (unsigned char)dst[0]);
3157 /* MAP_PRECOMPOSED */
3158 for (i = 1; i < 256; i++)
3160 src[0] = i;
3161 src[1] = '\0';
3162 SetLastError(0);
3163 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3164 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3165 ok(src[0] == dst[0],
3166 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3167 (unsigned char)src[0], (unsigned char)dst[0]);
3171 static void test_FoldStringW(void)
3173 int ret;
3174 unsigned int i, j;
3175 WCHAR src[256], dst[256], ch, prev_ch = 1;
3176 static const DWORD badFlags[] =
3179 MAP_PRECOMPOSED|MAP_COMPOSITE,
3180 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3181 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3183 /* Ranges of digits 0-9 : Must be sorted! */
3184 static const WCHAR digitRanges[] =
3186 0x0030, /* '0'-'9' */
3187 0x0660, /* Eastern Arabic */
3188 0x06F0, /* Arabic - Hindu */
3189 0x07C0, /* Nko */
3190 0x0966, /* Devengari */
3191 0x09E6, /* Bengalii */
3192 0x0A66, /* Gurmukhi */
3193 0x0AE6, /* Gujarati */
3194 0x0B66, /* Oriya */
3195 0x0BE6, /* Tamil - No 0 */
3196 0x0C66, /* Telugu */
3197 0x0CE6, /* Kannada */
3198 0x0D66, /* Maylayalam */
3199 0x0DE6, /* Sinhala Lith */
3200 0x0E50, /* Thai */
3201 0x0ED0, /* Laos */
3202 0x0F20, /* Tibet */
3203 0x0F29, /* Tibet half - 0 is out of sequence */
3204 0x1040, /* Myanmar */
3205 0x1090, /* Myanmar Shan */
3206 0x1368, /* Ethiopic - no 0 */
3207 0x17E0, /* Khmer */
3208 0x1810, /* Mongolian */
3209 0x1946, /* Limbu */
3210 0x19D0, /* New Tai Lue */
3211 0x1A80, /* Tai Tham Hora */
3212 0x1A90, /* Tai Tham Tham */
3213 0x1B50, /* Balinese */
3214 0x1BB0, /* Sundanese */
3215 0x1C40, /* Lepcha */
3216 0x1C50, /* Ol Chiki */
3217 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3218 0x2080, /* Subscript */
3219 0x245F, /* Circled - 0 is out of sequence */
3220 0x2473, /* Bracketed */
3221 0x2487, /* Full stop */
3222 0x24F4, /* Double Circled */
3223 0x2775, /* Inverted circled - No 0 */
3224 0x277F, /* Patterned circled - No 0 */
3225 0x2789, /* Inverted Patterned circled - No 0 */
3226 0x3020, /* Hangzhou */
3227 0xA620, /* Vai */
3228 0xA8D0, /* Saurashtra */
3229 0xA900, /* Kayah Li */
3230 0xA9D0, /* Javanese */
3231 0xA9F0, /* Myanmar Tai Laing */
3232 0xAA50, /* Cham */
3233 0xABF0, /* Meetei Mayek */
3234 0xff10, /* Pliene chasse (?) */
3235 0xffff /* Terminator */
3237 /* Digits which are represented, but out of sequence */
3238 static const WCHAR outOfSequenceDigits[] =
3240 0xB9, /* Superscript 1 */
3241 0xB2, /* Superscript 2 */
3242 0xB3, /* Superscript 3 */
3243 0x0C78, /* Telugu Fraction 0 */
3244 0x0C79, /* Telugu Fraction 1 */
3245 0x0C7A, /* Telugu Fraction 2 */
3246 0x0C7B, /* Telugu Fraction 3 */
3247 0x0C7C, /* Telugu Fraction 1 */
3248 0x0C7D, /* Telugu Fraction 2 */
3249 0x0C7E, /* Telugu Fraction 3 */
3250 0x0F33, /* Tibetan half zero */
3251 0x19DA, /* New Tai Lue Tham 1 */
3252 0x24EA, /* Circled 0 */
3253 0x24FF, /* Negative Circled 0 */
3254 0x3007, /* Ideographic number zero */
3255 '\0' /* Terminator */
3257 /* Digits in digitRanges for which no representation is available */
3258 static const WCHAR noDigitAvailable[] =
3260 0x0BE6, /* No Tamil 0 */
3261 0x0F29, /* No Tibetan half zero (out of sequence) */
3262 0x1368, /* No Ethiopic 0 */
3263 0x2473, /* No Bracketed 0 */
3264 0x2487, /* No 0 Full stop */
3265 0x24F4, /* No double circled 0 */
3266 0x2775, /* No inverted circled 0 */
3267 0x277F, /* No patterned circled */
3268 0x2789, /* No inverted Patterned circled */
3269 0x3020, /* No Hangzhou 0 */
3270 '\0' /* Terminator */
3272 static const WCHAR foldczone_src[] =
3274 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
3275 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3277 static const WCHAR foldczone_dst[] =
3279 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3281 static const WCHAR foldczone_todo_src[] =
3283 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3285 static const WCHAR foldczone_todo_dst[] =
3287 0x3cb,0x1f0,' ','a',0
3289 static const WCHAR foldczone_todo_broken_dst[] =
3291 0x3cb,0x1f0,0xa0,0xaa,0
3293 static const WCHAR ligatures_src[] =
3295 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
3296 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3297 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3298 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3299 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3300 0xfb04, 0xfb05, 0xfb06, '\0'
3302 static const WCHAR ligatures_dst[] =
3304 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3305 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3306 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3307 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3308 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3309 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3312 if (!pFoldStringW)
3314 win_skip("FoldStringW is not available\n");
3315 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3318 /* Invalid flag combinations */
3319 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3321 src[0] = dst[0] = '\0';
3322 SetLastError(0);
3323 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3324 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3326 win_skip("FoldStringW is not implemented\n");
3327 return;
3329 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3330 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3333 /* src & dst cannot be the same */
3334 SetLastError(0);
3335 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3336 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3337 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3339 /* src can't be NULL */
3340 SetLastError(0);
3341 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3342 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3343 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3345 /* srclen can't be 0 */
3346 SetLastError(0);
3347 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3348 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3349 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3351 /* dstlen can't be < 0 */
3352 SetLastError(0);
3353 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3354 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3355 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3357 /* Ret includes terminating NUL which is appended if srclen = -1 */
3358 SetLastError(0);
3359 src[0] = 'A';
3360 src[1] = '\0';
3361 dst[0] = '\0';
3362 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3363 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3364 ok(dst[0] == 'A' && dst[1] == '\0',
3365 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3366 'A', '\0', ret, dst[0], dst[1], GetLastError());
3368 /* If size is given, result is not NUL terminated */
3369 SetLastError(0);
3370 src[0] = 'A';
3371 src[1] = 'A';
3372 dst[0] = 'X';
3373 dst[1] = 'X';
3374 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3375 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3376 ok(dst[0] == 'A' && dst[1] == 'X',
3377 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3378 'A','X', ret, dst[0], dst[1], GetLastError());
3380 /* MAP_FOLDDIGITS */
3381 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3383 /* Check everything before this range */
3384 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3386 SetLastError(0);
3387 src[0] = ch;
3388 src[1] = dst[0] = '\0';
3389 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3390 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3392 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3393 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3394 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3395 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3396 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3397 "char %04x should not be a digit\n", ch );
3400 if (digitRanges[j] == 0xffff)
3401 break; /* Finished the whole code point space */
3403 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3405 WCHAR c;
3407 /* Map out of sequence characters */
3408 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3409 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3410 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3411 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3412 else c = ch;
3413 SetLastError(0);
3414 src[0] = c;
3415 src[1] = dst[0] = '\0';
3416 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3417 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3419 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3420 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3421 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3422 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3423 strchrW(noDigitAvailable, c),
3424 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3425 ch, '0' + digitRanges[j] - ch, dst[0]);
3427 prev_ch = ch;
3430 /* MAP_FOLDCZONE */
3431 SetLastError(0);
3432 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3433 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3434 "Got %d, error %d\n", ret, GetLastError());
3435 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3436 "MAP_FOLDCZONE: Expanded incorrectly\n");
3438 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3439 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3440 "Got %d, error %d\n", ret, GetLastError());
3441 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3442 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3443 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3445 /* MAP_EXPAND_LIGATURES */
3446 SetLastError(0);
3447 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3448 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3449 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3450 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3451 "Got %d, error %d\n", ret, GetLastError());
3452 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3453 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3456 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3461 #define LCID_OK(l) \
3462 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3463 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3464 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3465 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3466 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3468 static void test_ConvertDefaultLocale(void)
3470 LCID lcid;
3472 /* Doesn't change lcid, even if non default sublang/sort used */
3473 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3474 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3475 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3476 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3478 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3479 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3480 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3481 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3482 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3484 /* Invariant language is not treated specially */
3485 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3487 /* User/system default languages alone are not mapped */
3488 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3489 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3491 /* Default lcids */
3492 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3493 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3494 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3495 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3496 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3497 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3500 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3501 DWORD dwFlags, LONG_PTR lParam)
3503 if (winetest_debug > 1)
3504 trace("%08x, %s, %s, %08x, %08lx\n",
3505 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3507 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3508 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3510 /* If lParam is one, we are calling with flags defaulted from 0 */
3511 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3512 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3514 return TRUE;
3517 static void test_EnumSystemLanguageGroupsA(void)
3519 BOOL ret;
3521 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3523 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3524 return;
3527 /* No enumeration proc */
3528 SetLastError(0);
3529 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3530 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3532 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3533 return;
3535 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3536 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3538 /* Invalid flags */
3539 SetLastError(0);
3540 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3541 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3543 /* No flags - defaults to LGRPID_INSTALLED */
3544 SetLastError(0xdeadbeef);
3545 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3546 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3548 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3549 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3552 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3554 if (winetest_debug > 1)
3555 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3556 return TRUE;
3559 static void test_EnumSystemLocalesEx(void)
3561 BOOL ret;
3563 if (!pEnumSystemLocalesEx)
3565 win_skip( "EnumSystemLocalesEx not available\n" );
3566 return;
3568 SetLastError( 0xdeadbeef );
3569 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3570 ok( !ret, "should have failed\n" );
3571 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3572 SetLastError( 0xdeadbeef );
3573 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3574 ok( ret, "failed err %u\n", GetLastError() );
3577 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3578 LONG_PTR lParam)
3580 if (winetest_debug > 1)
3581 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3583 /* invalid locale enumerated on some platforms */
3584 if (lcid == 0)
3585 return TRUE;
3587 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3588 "Enumerated grp %d not valid\n", lgrpid);
3589 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3590 "Enumerated grp locale %04x not valid\n", lcid);
3591 return TRUE;
3594 static void test_EnumLanguageGroupLocalesA(void)
3596 BOOL ret;
3598 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3600 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3601 return;
3604 /* No enumeration proc */
3605 SetLastError(0);
3606 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3607 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3609 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3610 return;
3612 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3613 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3615 /* lgrpid too small */
3616 SetLastError(0);
3617 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3618 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3619 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3621 /* lgrpid too big */
3622 SetLastError(0);
3623 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3624 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3625 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3627 /* dwFlags is reserved */
3628 SetLastError(0);
3629 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3630 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3631 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3633 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3636 static void test_SetLocaleInfoA(void)
3638 BOOL bRet;
3639 LCID lcid = GetUserDefaultLCID();
3641 /* Null data */
3642 SetLastError(0);
3643 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3644 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3645 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3647 /* IDATE */
3648 SetLastError(0);
3649 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3650 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3651 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3653 /* ILDATE */
3654 SetLastError(0);
3655 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3656 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3657 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3660 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3662 if (winetest_debug > 1)
3663 trace("%s %08lx\n", value, lParam);
3664 return(TRUE);
3667 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3669 ok(!enumCount, "callback called again unexpected\n");
3670 enumCount++;
3671 return(FALSE);
3674 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3676 ok(0,"callback called unexpected\n");
3677 return(FALSE);
3680 static void test_EnumUILanguageA(void)
3682 BOOL ret;
3683 if (!pEnumUILanguagesA) {
3684 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3685 return;
3688 SetLastError(ERROR_SUCCESS);
3689 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3690 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3692 win_skip("EnumUILanguagesA is not implemented\n");
3693 return;
3695 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3697 enumCount = 0;
3698 SetLastError(ERROR_SUCCESS);
3699 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3700 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3702 SetLastError(ERROR_SUCCESS);
3703 ret = pEnumUILanguagesA(NULL, 0, 0);
3704 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3705 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3706 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3708 SetLastError(ERROR_SUCCESS);
3709 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3710 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3711 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3713 SetLastError(ERROR_SUCCESS);
3714 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3715 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3716 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3717 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3720 static char date_fmt_buf[1024];
3721 static WCHAR date_fmt_bufW[1024];
3723 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3725 lstrcatA(date_fmt_buf, fmt);
3726 lstrcatA(date_fmt_buf, "\n");
3727 return TRUE;
3730 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3732 lstrcatW(date_fmt_bufW, fmt);
3733 return FALSE;
3736 static void test_EnumDateFormatsA(void)
3738 char *p, buf[256];
3739 BOOL ret;
3740 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3742 date_fmt_buf[0] = 0;
3743 SetLastError(0xdeadbeef);
3744 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3745 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3747 win_skip("0 for dwFlags is not supported\n");
3749 else
3751 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3752 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3753 /* test the 1st enumerated format */
3754 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3755 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3756 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3757 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3760 date_fmt_buf[0] = 0;
3761 SetLastError(0xdeadbeef);
3762 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3763 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3765 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3767 else
3769 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3770 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3771 /* test the 1st enumerated format */
3772 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3773 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3774 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3775 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3778 date_fmt_buf[0] = 0;
3779 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3780 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3781 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3782 /* test the 1st enumerated format */
3783 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3784 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3785 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3786 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3788 date_fmt_buf[0] = 0;
3789 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3790 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3791 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3792 /* test the 1st enumerated format */
3793 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3794 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3795 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3796 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3798 date_fmt_buf[0] = 0;
3799 SetLastError(0xdeadbeef);
3800 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3801 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3803 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3804 return;
3806 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3807 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3808 /* test the 1st enumerated format */
3809 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3810 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3811 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3812 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3813 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3816 static void test_EnumTimeFormatsA(void)
3818 char *p, buf[256];
3819 BOOL ret;
3820 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3822 date_fmt_buf[0] = 0;
3823 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3824 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3825 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3826 /* test the 1st enumerated format */
3827 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3828 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3829 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3830 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3832 date_fmt_buf[0] = 0;
3833 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3834 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3835 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3836 /* test the 1st enumerated format */
3837 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3838 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3839 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3840 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3843 static void test_EnumTimeFormatsW(void)
3845 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3846 WCHAR bufW[256];
3847 BOOL ret;
3849 date_fmt_bufW[0] = 0;
3850 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3851 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3852 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3853 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3854 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3855 wine_dbgstr_w(bufW));
3857 date_fmt_bufW[0] = 0;
3858 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3859 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3860 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3861 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3862 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3863 wine_dbgstr_w(bufW));
3865 /* TIME_NOSECONDS is Win7+ feature */
3866 date_fmt_bufW[0] = 0;
3867 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3868 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3869 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3870 else {
3871 char buf[256];
3873 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3874 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3875 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3876 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3877 wine_dbgstr_w(bufW));
3879 /* EnumTimeFormatsA doesn't support this flag */
3880 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3881 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3882 GetLastError());
3884 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3885 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3886 GetLastError());
3888 /* And it's not supported by GetLocaleInfoA either */
3889 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3890 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3891 GetLastError());
3894 static void test_GetCPInfo(void)
3896 BOOL ret;
3897 CPINFO cpinfo;
3899 SetLastError(0xdeadbeef);
3900 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3901 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3902 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3903 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3905 SetLastError(0xdeadbeef);
3906 ret = GetCPInfo(CP_UTF7, &cpinfo);
3907 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3909 win_skip("Codepage CP_UTF7 is not installed/available\n");
3911 else
3913 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3914 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3915 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3916 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3917 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3918 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3921 SetLastError(0xdeadbeef);
3922 ret = GetCPInfo(CP_UTF8, &cpinfo);
3923 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3925 win_skip("Codepage CP_UTF8 is not installed/available\n");
3927 else
3929 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3930 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3931 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3932 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3933 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3934 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3935 "expected 4, got %u\n", cpinfo.MaxCharSize);
3940 * The CT_TYPE1 has varied over windows version.
3941 * The current target for correct behavior is windows 7.
3942 * There was a big shift between windows 2000 (first introduced) and windows Xp
3943 * Most of the old values below are from windows 2000.
3944 * A smaller subset of changes happened between windows Xp and Window vista/7
3946 static void test_GetStringTypeW(void)
3948 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3949 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3950 C1_SPACE | C1_BLANK | C1_DEFINED,
3951 C1_SPACE | C1_BLANK | C1_DEFINED,
3952 C1_SPACE | C1_BLANK | C1_DEFINED,
3953 C1_CNTRL | C1_BLANK | C1_DEFINED};
3954 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3955 C1_SPACE | C1_BLANK,
3956 C1_SPACE | C1_BLANK,
3957 C1_SPACE | C1_BLANK,
3958 C1_SPACE | C1_BLANK};
3960 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3962 /* Lu, Ll, Lt */
3963 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3964 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3965 C1_LOWER | C1_ALPHA,
3966 C1_UPPER | C1_LOWER | C1_ALPHA,
3967 C1_ALPHA};
3969 /* Sk, Sk, Mn, So, Me */
3970 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3971 /* Sc, Sm, No,*/
3972 0xffe0, 0xffe9, 0x2153};
3974 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3975 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3976 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3977 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3978 C1_ALPHA | C1_DEFINED,
3979 C1_CNTRL | C1_DEFINED,
3980 C1_PUNCT | C1_DEFINED,
3981 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3982 C1_ALPHA | C1_LOWER | C1_DEFINED,
3983 C1_ALPHA | C1_DEFINED };
3984 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3985 C1_ALPHA | C1_DEFINED,
3986 C1_CNTRL | C1_DEFINED,
3987 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3988 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3989 C1_ALPHA | C1_DEFINED,
3990 C1_DEFINED
3992 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3993 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3995 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3996 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3997 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3998 static const WCHAR lower_special[] = {0x2071, 0x207f};
3999 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
4000 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
4001 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
4002 0xfff9, 0xfffa, 0xfffb};
4003 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
4005 WORD types[20];
4006 WCHAR ch[2];
4007 BOOL ret;
4008 int i;
4010 /* NULL src */
4011 SetLastError(0xdeadbeef);
4012 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
4013 ok(!ret, "got %d\n", ret);
4014 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4016 SetLastError(0xdeadbeef);
4017 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
4018 ok(!ret, "got %d\n", ret);
4019 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4021 SetLastError(0xdeadbeef);
4022 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
4023 ok(!ret, "got %d\n", ret);
4024 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4026 memset(types,0,sizeof(types));
4027 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
4028 for (i = 0; i < 5; i++)
4029 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]);
4031 memset(types,0,sizeof(types));
4032 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
4033 for (i = 0; i < 3; i++)
4034 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]));
4035 memset(types,0,sizeof(types));
4036 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
4037 for (i = 0; i < 5; i++)
4038 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
4040 memset(types,0,sizeof(types));
4041 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
4042 for (i = 0; i < 8; i++)
4043 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);
4045 memset(types,0,sizeof(types));
4046 GetStringTypeW(CT_CTYPE1, changed, 7, types);
4047 for (i = 0; i < 7; i++)
4048 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]);
4050 memset(types,0,sizeof(types));
4051 GetStringTypeW(CT_CTYPE1, punct, 7, types);
4052 for (i = 0; i < 7; i++)
4053 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));
4056 memset(types,0,sizeof(types));
4057 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
4058 for (i = 0; i < 12; i++)
4059 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);
4061 memset(types,0,sizeof(types));
4062 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
4063 for (i = 0; i < 3; i++)
4064 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);
4066 memset(types,0,sizeof(types));
4067 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
4068 for (i = 0; i < 2; i++)
4069 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);
4071 memset(types,0,sizeof(types));
4072 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4073 for (i = 0; i < 20; i++)
4074 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);
4076 memset(types,0,sizeof(types));
4077 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4078 for (i = 0; i < 3; i++)
4079 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 );
4081 /* surrogate pairs */
4082 ch[0] = 0xd800;
4083 memset(types, 0, sizeof(types));
4084 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4085 if (types[0] == C3_NOTAPPLICABLE)
4086 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4087 else {
4088 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4090 ch[0] = 0xdc00;
4091 memset(types, 0, sizeof(types));
4092 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4093 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4096 /* Zl, Zp categories */
4097 ch[0] = 0x2028;
4098 ch[1] = 0x2029;
4099 memset(types, 0, sizeof(types));
4100 GetStringTypeW(CT_CTYPE1, ch, 2, types);
4101 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4102 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4104 /* check Arabic range for kashida flag */
4105 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4107 types[0] = 0;
4108 ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4109 ok(ret, "%#x: failed %d\n", ch[0], ret);
4110 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4111 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4112 else
4113 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4117 static void test_IdnToNameprepUnicode(void)
4119 struct {
4120 DWORD in_len;
4121 const WCHAR in[64];
4122 DWORD ret;
4123 DWORD broken_ret;
4124 const WCHAR out[64];
4125 DWORD flags;
4126 DWORD err;
4127 DWORD todo;
4128 } test_data[] = {
4130 5, {'t','e','s','t',0},
4131 5, 5, {'t','e','s','t',0},
4132 0, 0xdeadbeef
4135 3, {'a',0xe111,'b'},
4136 0, 0, {0},
4137 0, ERROR_INVALID_NAME
4140 4, {'t',0,'e',0},
4141 0, 0, {0},
4142 0, ERROR_INVALID_NAME
4145 1, {'T',0},
4146 1, 1, {'T',0},
4147 0, 0xdeadbeef
4150 1, {0},
4151 0, 0, {0},
4152 0, ERROR_INVALID_NAME
4155 6, {' ','-','/','[',']',0},
4156 6, 6, {' ','-','/','[',']',0},
4157 0, 0xdeadbeef
4160 3, {'a','-','a'},
4161 3, 3, {'a','-','a'},
4162 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4165 3, {'a','a','-'},
4166 0, 0, {0},
4167 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4169 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4170 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4171 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4172 0, 0xdeadbeef, TRUE
4175 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4176 2, 0, {'t',0},
4177 0, 0xdeadbeef
4179 { /* Another example of incorrectly working FoldString (composition) */
4180 2, {0x3b0, 0},
4181 2, 2, {0x3b0, 0},
4182 0, 0xdeadbeef, TRUE
4185 2, {0x221, 0},
4186 0, 2, {0},
4187 0, ERROR_NO_UNICODE_TRANSLATION
4190 2, {0x221, 0},
4191 2, 2, {0x221, 0},
4192 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4195 5, {'a','.','.','a',0},
4196 0, 0, {0},
4197 0, ERROR_INVALID_NAME
4200 3, {'a','.',0},
4201 3, 3, {'a','.',0},
4202 0, 0xdeadbeef
4206 WCHAR buf[1024];
4207 DWORD i, ret, err;
4209 if (!pIdnToNameprepUnicode)
4211 win_skip("IdnToNameprepUnicode is not available\n");
4212 return;
4215 ret = pIdnToNameprepUnicode(0, test_data[0].in,
4216 test_data[0].in_len, NULL, 0);
4217 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4219 SetLastError(0xdeadbeef);
4220 ret = pIdnToNameprepUnicode(0, test_data[1].in,
4221 test_data[1].in_len, NULL, 0);
4222 err = GetLastError();
4223 ok(ret == test_data[1].ret, "ret = %d\n", ret);
4224 ok(err == test_data[1].err, "err = %d\n", err);
4226 SetLastError(0xdeadbeef);
4227 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
4228 buf, sizeof(buf)/sizeof(WCHAR));
4229 err = GetLastError();
4230 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4231 ok(err == 0xdeadbeef, "err = %d\n", err);
4233 SetLastError(0xdeadbeef);
4234 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
4235 buf, sizeof(buf)/sizeof(WCHAR));
4236 err = GetLastError();
4237 ok(ret == 0, "ret = %d\n", ret);
4238 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4240 SetLastError(0xdeadbeef);
4241 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
4242 buf, sizeof(buf)/sizeof(WCHAR));
4243 err = GetLastError();
4244 ok(ret == 0, "ret = %d\n", ret);
4245 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4247 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4248 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
4249 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4251 SetLastError(0xdeadbeef);
4252 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4253 err = GetLastError();
4254 ok(ret == 0, "ret = %d\n", ret);
4255 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4257 SetLastError(0xdeadbeef);
4258 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4259 err = GetLastError();
4260 ok(ret == 0, "ret = %d\n", ret);
4261 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4262 "err = %d\n", err);
4264 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4266 SetLastError(0xdeadbeef);
4267 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
4268 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
4269 err = GetLastError();
4271 todo_wine_if (test_data[i].todo)
4272 ok(ret == test_data[i].ret ||
4273 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4275 if(ret != test_data[i].ret)
4276 continue;
4278 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4279 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4280 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4284 static void test_IdnToAscii(void)
4286 struct {
4287 DWORD in_len;
4288 const WCHAR in[64];
4289 DWORD ret;
4290 const WCHAR out[64];
4291 DWORD flags;
4292 DWORD err;
4293 } test_data[] = {
4295 5, {'T','e','s','t',0},
4296 5, {'T','e','s','t',0},
4297 0, 0xdeadbeef
4300 5, {'T','e',0x017c,'s','t',0},
4301 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4302 0, 0xdeadbeef
4305 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4306 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4307 0, 0xdeadbeef
4310 3, {0x0105,'.',0},
4311 9, {'x','n','-','-','2','d','a','.',0},
4312 0, 0xdeadbeef
4315 10, {'h','t','t','p',':','/','/','t',0x0106,0},
4316 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4317 0, 0xdeadbeef
4320 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4321 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4322 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4323 0, 0xdeadbeef
4326 2, {0x221,0},
4327 8, {'x','n','-','-','6','l','a',0},
4328 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4332 WCHAR buf[1024];
4333 DWORD i, ret, err;
4335 if (!pIdnToAscii)
4337 win_skip("IdnToAscii is not available\n");
4338 return;
4341 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4343 SetLastError(0xdeadbeef);
4344 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4345 test_data[i].in_len, buf, sizeof(buf));
4346 err = GetLastError();
4347 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4348 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4349 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4350 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4354 static void test_IdnToUnicode(void)
4356 struct {
4357 DWORD in_len;
4358 const WCHAR in[64];
4359 DWORD ret;
4360 const WCHAR out[64];
4361 DWORD flags;
4362 DWORD err;
4363 } test_data[] = {
4365 5, {'T','e','s','.',0},
4366 5, {'T','e','s','.',0},
4367 0, 0xdeadbeef
4370 2, {0x105,0},
4371 0, {0},
4372 0, ERROR_INVALID_NAME
4375 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4376 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4377 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4378 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4379 0x05d1,0x05e8,0x05d9,0x05ea,0},
4380 0, 0xdeadbeef
4383 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4384 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4385 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4386 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4387 0, 0xdeadbeef
4390 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4391 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4392 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4393 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4394 0, {0},
4395 0, ERROR_INVALID_NAME
4398 8, {'x','n','-','-','6','l','a',0},
4399 2, {0x221,0},
4400 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4404 WCHAR buf[1024];
4405 DWORD i, ret, err;
4407 if (!pIdnToUnicode)
4409 win_skip("IdnToUnicode is not available\n");
4410 return;
4413 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4415 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4416 test_data[i].in_len, NULL, 0);
4417 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4419 SetLastError(0xdeadbeef);
4420 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4421 test_data[i].in_len, buf, sizeof(buf));
4422 err = GetLastError();
4423 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4424 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4425 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4426 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4430 static void test_GetLocaleInfoEx(void)
4432 static const WCHAR enW[] = {'e','n',0};
4433 WCHAR bufferW[80], buffer2[80];
4434 INT ret;
4436 if (!pGetLocaleInfoEx)
4438 win_skip("GetLocaleInfoEx not supported\n");
4439 return;
4442 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4443 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4444 if (ret)
4446 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4447 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4448 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4449 static const WCHAR usaW[] = {'U','S','A',0};
4450 static const WCHAR enuW[] = {'E','N','U',0};
4451 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4452 DWORD val;
4454 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4455 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4457 SetLastError(0xdeadbeef);
4458 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4459 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4461 SetLastError(0xdeadbeef);
4462 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4463 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4465 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4466 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4467 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4469 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4470 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4471 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4473 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4474 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4475 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4477 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4478 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4479 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4480 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4482 skip("Non-English locale\n");
4484 else
4485 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4487 bufferW[0] = 0;
4488 SetLastError(0xdeadbeef);
4489 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4490 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4492 while (*ptr->name)
4494 val = 0;
4495 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4496 todo_wine_if (ptr->todo)
4497 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4498 bufferW[0] = 0;
4499 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4500 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4501 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4502 ptr++;
4505 ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4506 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4507 ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR));
4508 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4509 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4513 static void test_IsValidLocaleName(void)
4515 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4516 static const WCHAR zzW[] = {'z','z',0};
4517 static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0};
4518 static const WCHAR zzzzW[] = {'z','z','z','z',0};
4519 BOOL ret;
4521 if (!pIsValidLocaleName)
4523 win_skip("IsValidLocaleName not supported\n");
4524 return;
4527 ret = pIsValidLocaleName(enusW);
4528 ok(ret, "IsValidLocaleName failed\n");
4529 ret = pIsValidLocaleName(zzW);
4530 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4531 ret = pIsValidLocaleName(zz_zzW);
4532 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4533 ret = pIsValidLocaleName(zzzzW);
4534 ok(!ret, "IsValidLocaleName should have failed\n");
4535 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4536 ok(ret, "IsValidLocaleName failed\n");
4537 ret = pIsValidLocaleName(NULL);
4538 ok(!ret, "IsValidLocaleName should have failed\n");
4541 static void test_CompareStringOrdinal(void)
4543 INT ret;
4544 WCHAR test1[] = { 't','e','s','t',0 };
4545 WCHAR test2[] = { 'T','e','S','t',0 };
4546 WCHAR test3[] = { 't','e','s','t','3',0 };
4547 WCHAR null1[] = { 'a',0,'a',0 };
4548 WCHAR null2[] = { 'a',0,'b',0 };
4549 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4550 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4551 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4552 WCHAR coop2[] = { 'c','o','o','p',0 };
4553 WCHAR nonascii1[] = { 0x0102,0 };
4554 WCHAR nonascii2[] = { 0x0201,0 };
4555 WCHAR ch1, ch2;
4557 if (!pCompareStringOrdinal)
4559 win_skip("CompareStringOrdinal not supported\n");
4560 return;
4563 /* Check errors */
4564 SetLastError(0xdeadbeef);
4565 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4566 ok(!ret, "Got %u, expected 0\n", ret);
4567 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4568 SetLastError(0xdeadbeef);
4569 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4570 ok(!ret, "Got %u, expected 0\n", ret);
4571 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4572 SetLastError(0xdeadbeef);
4573 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4574 ok(!ret, "Got %u, expected 0\n", ret);
4575 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4577 /* Check case */
4578 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4579 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4580 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4581 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4582 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4583 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4584 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4585 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4587 /* Check different sizes */
4588 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4589 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4590 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4591 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4593 /* Check null character */
4594 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4595 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4596 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4597 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4598 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4599 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4600 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4601 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4603 /* Check ordinal behaviour */
4604 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4605 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4606 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4607 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4608 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4609 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4610 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4611 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4613 for (ch1 = 0; ch1 < 512; ch1++)
4615 for (ch2 = 0; ch2 < 1024; ch2++)
4617 int diff = ch1 - ch2;
4618 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4619 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4620 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4621 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4622 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4623 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4624 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4629 static void test_GetGeoInfo(void)
4631 char buffA[20];
4632 INT ret;
4634 if (!pGetGeoInfoA)
4636 win_skip("GetGeoInfo is not available.\n");
4637 return;
4640 /* unassigned id */
4641 SetLastError(0xdeadbeef);
4642 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4643 ok(ret == 0, "got %d\n", ret);
4644 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4646 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4647 ok(ret == 3, "got %d\n", ret);
4649 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4650 ok(ret == 4, "got %d\n", ret);
4652 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4653 ok(ret == 3, "got %d\n", ret);
4654 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4656 /* buffer pointer not NULL, length is 0 - return required length */
4657 buffA[0] = 'a';
4658 SetLastError(0xdeadbeef);
4659 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4660 ok(ret == 3, "got %d\n", ret);
4661 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4663 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4664 ok(ret == 4, "got %d\n", ret);
4665 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4667 /* shorter buffer */
4668 SetLastError(0xdeadbeef);
4669 buffA[1] = buffA[2] = 0;
4670 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4671 ok(ret == 0, "got %d\n", ret);
4672 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4673 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4675 /* GEO_NATION returns GEOID in a string form */
4676 buffA[0] = 0;
4677 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4678 ok(ret == 4, "got %d\n", ret);
4679 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4681 /* GEO_PARENT */
4682 buffA[0] = 0;
4683 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4684 if (ret == 0)
4685 win_skip("GEO_PARENT not supported.\n");
4686 else
4688 ok(ret == 6, "got %d\n", ret);
4689 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4692 buffA[0] = 0;
4693 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4694 if (ret == 0)
4695 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4696 else
4698 ok(ret == 4, "got %d\n", ret);
4699 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4702 /* try invalid type value */
4703 SetLastError(0xdeadbeef);
4704 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4705 ok(ret == 0, "got %d\n", ret);
4706 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4709 static int geoidenum_count;
4710 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4712 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4713 ok(ret == 3, "got %d for %d\n", ret, geoid);
4714 /* valid geoid starts at 2 */
4715 ok(geoid >= 2, "got geoid %d\n", geoid);
4717 return geoidenum_count++ < 5;
4720 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4722 geoidenum_count++;
4723 return TRUE;
4726 static void test_EnumSystemGeoID(void)
4728 BOOL ret;
4730 if (!pEnumSystemGeoID)
4732 win_skip("EnumSystemGeoID is not available.\n");
4733 return;
4736 SetLastError(0xdeadbeef);
4737 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4738 ok(!ret, "got %d\n", ret);
4739 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4741 SetLastError(0xdeadbeef);
4742 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4743 ok(!ret, "got %d\n", ret);
4744 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4746 SetLastError(0xdeadbeef);
4747 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4748 ok(!ret, "got %d\n", ret);
4749 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4751 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4752 ok(ret, "got %d\n", ret);
4754 /* only the first level is enumerated, not the whole hierarchy */
4755 geoidenum_count = 0;
4756 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4757 if (ret == 0)
4758 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4759 else
4760 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4762 geoidenum_count = 0;
4763 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4764 if (ret == 0)
4765 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4766 else
4768 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4770 geoidenum_count = 0;
4771 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4772 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4776 struct invariant_entry {
4777 const char *name;
4778 int id;
4779 const char *expect, *expect2;
4782 #define X(x) #x, x
4783 static const struct invariant_entry invariant_list[] = {
4784 { X(LOCALE_ILANGUAGE), "007f" },
4785 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4786 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4787 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4788 { X(LOCALE_ICOUNTRY), "1" },
4789 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4790 { X(LOCALE_SABBREVCTRYNAME), "IVC", "" },
4791 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4792 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4793 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4794 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4795 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4796 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4797 { X(LOCALE_SLIST), "," },
4798 { X(LOCALE_IMEASURE), "0" },
4799 { X(LOCALE_SDECIMAL), "." },
4800 { X(LOCALE_STHOUSAND), "," },
4801 { X(LOCALE_SGROUPING), "3;0" },
4802 { X(LOCALE_IDIGITS), "2" },
4803 { X(LOCALE_ILZERO), "1" },
4804 { X(LOCALE_INEGNUMBER), "1" },
4805 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4806 { X(LOCALE_SCURRENCY), "\x00a4" },
4807 { X(LOCALE_SINTLSYMBOL), "XDR" },
4808 { X(LOCALE_SMONDECIMALSEP), "." },
4809 { X(LOCALE_SMONTHOUSANDSEP), "," },
4810 { X(LOCALE_SMONGROUPING), "3;0" },
4811 { X(LOCALE_ICURRDIGITS), "2" },
4812 { X(LOCALE_IINTLCURRDIGITS), "2" },
4813 { X(LOCALE_ICURRENCY), "0" },
4814 { X(LOCALE_INEGCURR), "0" },
4815 { X(LOCALE_SDATE), "/" },
4816 { X(LOCALE_STIME), ":" },
4817 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4818 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4819 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4820 { X(LOCALE_IDATE), "0" },
4821 { X(LOCALE_ILDATE), "1" },
4822 { X(LOCALE_ITIME), "1" },
4823 { X(LOCALE_ITIMEMARKPOSN), "0" },
4824 { X(LOCALE_ICENTURY), "1" },
4825 { X(LOCALE_ITLZERO), "1" },
4826 { X(LOCALE_IDAYLZERO), "1" },
4827 { X(LOCALE_IMONLZERO), "1" },
4828 { X(LOCALE_S1159), "AM" },
4829 { X(LOCALE_S2359), "PM" },
4830 { X(LOCALE_ICALENDARTYPE), "1" },
4831 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4832 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4833 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4834 { X(LOCALE_SDAYNAME1), "Monday" },
4835 { X(LOCALE_SDAYNAME2), "Tuesday" },
4836 { X(LOCALE_SDAYNAME3), "Wednesday" },
4837 { X(LOCALE_SDAYNAME4), "Thursday" },
4838 { X(LOCALE_SDAYNAME5), "Friday" },
4839 { X(LOCALE_SDAYNAME6), "Saturday" },
4840 { X(LOCALE_SDAYNAME7), "Sunday" },
4841 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4842 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4843 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4844 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4845 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4846 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4847 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4848 { X(LOCALE_SMONTHNAME1), "January" },
4849 { X(LOCALE_SMONTHNAME2), "February" },
4850 { X(LOCALE_SMONTHNAME3), "March" },
4851 { X(LOCALE_SMONTHNAME4), "April" },
4852 { X(LOCALE_SMONTHNAME5), "May" },
4853 { X(LOCALE_SMONTHNAME6), "June" },
4854 { X(LOCALE_SMONTHNAME7), "July" },
4855 { X(LOCALE_SMONTHNAME8), "August" },
4856 { X(LOCALE_SMONTHNAME9), "September" },
4857 { X(LOCALE_SMONTHNAME10), "October" },
4858 { X(LOCALE_SMONTHNAME11), "November" },
4859 { X(LOCALE_SMONTHNAME12), "December" },
4860 { X(LOCALE_SMONTHNAME13), "" },
4861 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4862 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4863 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4864 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4865 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4866 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4867 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4868 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4869 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4870 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4871 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4872 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4873 { X(LOCALE_SABBREVMONTHNAME13), "" },
4874 { X(LOCALE_SPOSITIVESIGN), "+" },
4875 { X(LOCALE_SNEGATIVESIGN), "-" },
4876 { X(LOCALE_IPOSSIGNPOSN), "3" },
4877 { X(LOCALE_INEGSIGNPOSN), "0" },
4878 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4879 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4880 { X(LOCALE_INEGSYMPRECEDES), "1" },
4881 { X(LOCALE_INEGSEPBYSPACE), "0" },
4882 { X(LOCALE_SISO639LANGNAME), "iv" },
4883 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4884 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4885 { X(LOCALE_IPAPERSIZE), "9" },
4886 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4887 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4888 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4889 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4890 { X(LOCALE_SNAME), "" },
4891 { X(LOCALE_SSCRIPTS), "Latn;" },
4892 { 0 }
4894 #undef X
4896 static void test_invariant(void)
4898 int ret;
4899 int len;
4900 char buffer[BUFFER_SIZE];
4901 const struct invariant_entry *ptr = invariant_list;
4903 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4905 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4906 return;
4909 while (ptr->name)
4911 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4912 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4913 win_skip("not supported\n"); /* winxp/win2k3 */
4914 else
4916 len = strlen(ptr->expect)+1; /* include \0 */
4917 ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
4918 "For id %d, expected ret == %d, got %d, error %d\n",
4919 ptr->id, len, ret, GetLastError());
4920 ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
4921 "For id %d, Expected %s, got '%s'\n",
4922 ptr->id, ptr->expect, buffer);
4925 ptr++;
4928 if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) ||
4929 (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
4931 skip("Non US-English locale\n");
4933 else
4935 /* some locales translate these */
4936 static const char lang[] = "Invariant Language (Invariant Country)";
4937 static const char cntry[] = "Invariant Country";
4938 static const char sortm[] = "Math Alphanumerics";
4939 static const char sortd[] = "Default"; /* win2k3 */
4941 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4942 len = lstrlenA(lang) + 1;
4943 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4944 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4946 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4947 len = lstrlenA(cntry) + 1;
4948 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4949 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4951 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4952 if (ret == lstrlenA(sortm)+1)
4953 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4954 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4955 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4956 else
4957 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4958 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4962 static void test_GetSystemPreferredUILanguages(void)
4964 BOOL ret;
4965 ULONG count, size, size_id, size_name, size_buffer;
4966 WCHAR *buffer;
4969 if (!pGetSystemPreferredUILanguages)
4971 win_skip("GetSystemPreferredUILanguages is not available.\n");
4972 return;
4975 /* (in)valid first parameter */
4976 count = 0xdeadbeef;
4977 size = 0;
4978 SetLastError(0xdeadbeef);
4979 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4980 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4981 ok(count, "Expected count > 0\n");
4982 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4984 count = 0xdeadbeef;
4985 size = 0;
4986 SetLastError(0xdeadbeef);
4987 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4988 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4989 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4990 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4992 count = 0xdeadbeef;
4993 size = 0;
4994 SetLastError(0xdeadbeef);
4995 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4996 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4997 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4998 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5000 count = 0xdeadbeef;
5001 size = 0;
5002 SetLastError(0xdeadbeef);
5003 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
5004 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5005 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5006 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5008 count = 0xdeadbeef;
5009 size = 0;
5010 SetLastError(0xdeadbeef);
5011 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5012 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5013 ok(count, "Expected count > 0\n");
5014 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5016 count = 0xdeadbeef;
5017 size = 0;
5018 SetLastError(0xdeadbeef);
5019 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5020 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5021 ok(count, "Expected count > 0\n");
5022 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5024 /* second parameter
5025 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
5026 * -> unhandled exception c0000005
5029 /* invalid third parameter */
5030 count = 0xdeadbeef;
5031 size = 1;
5032 SetLastError(0xdeadbeef);
5033 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5034 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5035 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5036 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5038 /* fourth parameter
5039 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
5040 * -> unhandled exception c0000005
5043 count = 0xdeadbeef;
5044 size_id = 0;
5045 SetLastError(0xdeadbeef);
5046 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5047 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5048 ok(count, "Expected count > 0\n");
5049 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5051 count = 0xdeadbeef;
5052 size_name = 0;
5053 SetLastError(0xdeadbeef);
5054 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5055 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5056 ok(count, "Expected count > 0\n");
5057 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5059 size_buffer = max(size_id, size_name);
5060 if(!size_buffer)
5062 skip("No valid buffer size\n");
5063 return;
5066 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5067 if (!buffer)
5069 skip("Failed to allocate memory for %d chars\n", size_buffer);
5070 return;
5073 count = 0xdeadbeef;
5074 size = size_buffer;
5075 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5076 SetLastError(0xdeadbeef);
5077 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5078 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5079 ok(count, "Expected count > 0\n");
5080 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5081 if (ret && size % 6 == 1)
5082 ok(!buffer[size -2] && !buffer[size -1],
5083 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5084 buffer[size -2], buffer[size -1]);
5086 count = 0xdeadbeef;
5087 size = size_buffer;
5088 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5089 SetLastError(0xdeadbeef);
5090 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5091 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5092 ok(count, "Expected count > 0\n");
5093 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5094 if (ret && size % 5 == 1)
5095 ok(!buffer[size -2] && !buffer[size -1],
5096 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5097 buffer[size -2], buffer[size -1]);
5099 count = 0xdeadbeef;
5100 size = size_buffer;
5101 SetLastError(0xdeadbeef);
5102 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5103 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5104 ok(count, "Expected count > 0\n");
5105 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5106 if (ret && size % 5 == 1)
5107 ok(!buffer[size -2] && !buffer[size -1],
5108 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5109 buffer[size -2], buffer[size -1]);
5111 count = 0xdeadbeef;
5112 size = 0;
5113 SetLastError(0xdeadbeef);
5114 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5115 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5116 ok(count, "Expected count > 0\n");
5117 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5118 if (ret && size % 6 == 1)
5119 ok(!buffer[size -2] && !buffer[size -1],
5120 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5121 buffer[size -2], buffer[size -1]);
5123 count = 0xdeadbeef;
5124 size = 1;
5125 SetLastError(0xdeadbeef);
5126 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5127 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5128 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5129 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5131 count = 0xdeadbeef;
5132 size = size_id -1;
5133 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5134 SetLastError(0xdeadbeef);
5135 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5136 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5137 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5138 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5140 count = 0xdeadbeef;
5141 size = size_id -2;
5142 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5143 SetLastError(0xdeadbeef);
5144 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5145 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5146 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5147 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5149 HeapFree(GetProcessHeap(), 0, buffer);
5152 static void test_GetThreadPreferredUILanguages(void)
5154 BOOL ret;
5155 ULONG count, size;
5156 WCHAR *buf;
5158 if (!pGetThreadPreferredUILanguages)
5160 win_skip("GetThreadPreferredUILanguages is not available.\n");
5161 return;
5164 size = count = 0;
5165 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5166 ok(ret, "got %u\n", GetLastError());
5167 ok(count, "expected count > 0\n");
5168 ok(size, "expected size > 0\n");
5170 count = 0;
5171 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5172 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5173 ok(ret, "got %u\n", GetLastError());
5174 ok(count, "expected count > 0\n");
5175 HeapFree(GetProcessHeap(), 0, buf);
5178 static void test_GetUserPreferredUILanguages(void)
5180 BOOL ret;
5181 ULONG count, size, size_id, size_name, size_buffer;
5182 WCHAR *buffer;
5185 if (!pGetUserPreferredUILanguages)
5187 win_skip("GetUserPreferredUILanguages is not available.\n");
5188 return;
5191 count = 0xdeadbeef;
5192 size = 0;
5193 SetLastError(0xdeadbeef);
5194 ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5195 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5196 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5197 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5199 count = 0xdeadbeef;
5200 size = 0;
5201 SetLastError(0xdeadbeef);
5202 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5203 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5204 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5205 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5207 count = 0xdeadbeef;
5208 size = 0;
5209 SetLastError(0xdeadbeef);
5210 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5211 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5212 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5213 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5215 count = 0xdeadbeef;
5216 size = 1;
5217 SetLastError(0xdeadbeef);
5218 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5219 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5220 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5221 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5223 count = 0xdeadbeef;
5224 size_id = 0;
5225 SetLastError(0xdeadbeef);
5226 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5227 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5228 ok(count, "Expected count > 0\n");
5229 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5231 count = 0xdeadbeef;
5232 size_name = 0;
5233 SetLastError(0xdeadbeef);
5234 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5235 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5236 ok(count, "Expected count > 0\n");
5237 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5239 size_buffer = max(size_id, size_name);
5240 if(!size_buffer)
5242 skip("No valid buffer size\n");
5243 return;
5246 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5248 count = 0xdeadbeef;
5249 size = size_buffer;
5250 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5251 SetLastError(0xdeadbeef);
5252 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5253 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5254 ok(count, "Expected count > 0\n");
5255 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5256 if (ret && size % 6 == 1)
5257 ok(!buffer[size -2] && !buffer[size -1],
5258 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5259 buffer[size -2], buffer[size -1]);
5261 count = 0xdeadbeef;
5262 size = size_buffer;
5263 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5264 SetLastError(0xdeadbeef);
5265 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5266 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5267 ok(count, "Expected count > 0\n");
5268 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5269 if (ret && size % 5 == 1)
5270 ok(!buffer[size -2] && !buffer[size -1],
5271 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5272 buffer[size -2], buffer[size -1]);
5274 count = 0xdeadbeef;
5275 size = size_buffer;
5276 SetLastError(0xdeadbeef);
5277 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5278 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5279 ok(count, "Expected count > 0\n");
5280 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5281 if (ret && size % 5 == 1)
5282 ok(!buffer[size -2] && !buffer[size -1],
5283 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5284 buffer[size -2], buffer[size -1]);
5286 count = 0xdeadbeef;
5287 size = 1;
5288 SetLastError(0xdeadbeef);
5289 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5290 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5291 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5292 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5294 count = 0xdeadbeef;
5295 size = size_id -1;
5296 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5297 SetLastError(0xdeadbeef);
5298 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5299 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5300 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5301 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5303 count = 0xdeadbeef;
5304 size = size_id -2;
5305 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5306 SetLastError(0xdeadbeef);
5307 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5308 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5309 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5310 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5312 HeapFree(GetProcessHeap(), 0, buffer);
5315 START_TEST(locale)
5317 InitFunctionPointers();
5319 test_EnumTimeFormatsA();
5320 test_EnumTimeFormatsW();
5321 test_EnumDateFormatsA();
5322 test_GetLocaleInfoA();
5323 test_GetLocaleInfoW();
5324 test_GetLocaleInfoEx();
5325 test_GetTimeFormatA();
5326 test_GetTimeFormatEx();
5327 test_GetDateFormatA();
5328 test_GetDateFormatEx();
5329 test_GetDateFormatW();
5330 test_GetCurrencyFormatA(); /* Also tests the W version */
5331 test_GetNumberFormatA(); /* Also tests the W version */
5332 test_GetNumberFormatEx();
5333 test_CompareStringA();
5334 test_CompareStringW();
5335 test_CompareStringEx();
5336 test_LCMapStringA();
5337 test_LCMapStringW();
5338 test_LCMapStringEx();
5339 test_LocaleNameToLCID();
5340 test_FoldStringA();
5341 test_FoldStringW();
5342 test_ConvertDefaultLocale();
5343 test_EnumSystemLanguageGroupsA();
5344 test_EnumSystemLocalesEx();
5345 test_EnumLanguageGroupLocalesA();
5346 test_SetLocaleInfoA();
5347 test_EnumUILanguageA();
5348 test_GetCPInfo();
5349 test_GetStringTypeW();
5350 test_IdnToNameprepUnicode();
5351 test_IdnToAscii();
5352 test_IdnToUnicode();
5353 test_IsValidLocaleName();
5354 test_CompareStringOrdinal();
5355 test_GetGeoInfo();
5356 test_EnumSystemGeoID();
5357 test_invariant();
5358 test_GetSystemPreferredUILanguages();
5359 test_GetThreadPreferredUILanguages();
5360 test_GetUserPreferredUILanguages();
5361 /* this requires collation table patch to make it MS compatible */
5362 if (0) test_sorting();