kernel32: GetLongPathName should fail when called with a wildcard.
[wine.git] / dlls / kernel32 / tests / locale.c
blobd3eb2ecf15e8710b46da15b654aae5b19f41e4e0
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);
106 static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
107 static LANGID (WINAPI *pSetThreadUILanguage)(LANGID);
108 static LANGID (WINAPI *pGetThreadUILanguage)(VOID);
109 static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT);
111 static void InitFunctionPointers(void)
113 HMODULE mod = GetModuleHandleA("kernel32");
115 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
116 X(GetTimeFormatEx);
117 X(GetDateFormatEx);
118 X(EnumSystemLanguageGroupsA);
119 X(EnumLanguageGroupLocalesA);
120 X(LocaleNameToLCID);
121 X(LCIDToLocaleName);
122 X(LCMapStringEx);
123 X(FoldStringA);
124 X(FoldStringW);
125 X(IsValidLanguageGroup);
126 X(EnumUILanguagesA);
127 X(EnumSystemLocalesEx);
128 X(IdnToNameprepUnicode);
129 X(IdnToAscii);
130 X(IdnToUnicode);
131 X(GetLocaleInfoEx);
132 X(IsValidLocaleName);
133 X(CompareStringOrdinal);
134 X(CompareStringEx);
135 X(GetGeoInfoA);
136 X(GetGeoInfoW);
137 X(EnumSystemGeoID);
138 X(GetSystemPreferredUILanguages);
139 X(GetThreadPreferredUILanguages);
140 X(GetUserPreferredUILanguages);
141 X(GetNumberFormatEx);
142 X(FindNLSStringEx);
143 X(SetThreadUILanguage);
144 X(GetThreadUILanguage);
145 X(NormalizeString);
147 mod = GetModuleHandleA("ntdll");
148 X(RtlUpcaseUnicodeChar);
149 #undef X
152 #define eq(received, expected, label, type) \
153 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
154 (label), (received), (expected))
156 #define BUFFER_SIZE 128
158 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
159 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
160 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
161 "Expected '%s', got '%s'\n", Expected, buffer)
163 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,ARRAY_SIZE(input)); \
164 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,ARRAY_SIZE(Expected)); \
165 SetLastError(0xdeadbeef); buffer[0] = '\0'
166 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
167 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
169 #define NUO LOCALE_NOUSEROVERRIDE
171 static void test_GetLocaleInfoA(void)
173 int ret;
174 int len;
175 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
176 char buffer[BUFFER_SIZE];
177 char expected[BUFFER_SIZE];
178 DWORD val;
180 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
182 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
183 ok(ret, "got %d\n", ret);
184 ok(val == lcid, "got 0x%08x\n", val);
186 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
187 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
188 assumes SUBLANG_NEUTRAL for zh */
189 memset(expected, 0, ARRAY_SIZE(expected));
190 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected));
191 SetLastError(0xdeadbeef);
192 memset(buffer, 0, ARRAY_SIZE(buffer));
193 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer));
194 ok((ret == len) && !lstrcmpA(buffer, expected),
195 "got %d with '%s' (expected %d with '%s')\n",
196 ret, buffer, len, expected);
198 memset(expected, 0, ARRAY_SIZE(expected));
199 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected));
200 if (len) {
201 SetLastError(0xdeadbeef);
202 memset(buffer, 0, ARRAY_SIZE(buffer));
203 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer));
204 ok((ret == len) && !lstrcmpA(buffer, expected),
205 "got %d with '%s' (expected %d with '%s')\n",
206 ret, buffer, len, expected);
208 else
209 win_skip("LANG_ARABIC not installed\n");
211 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
212 memset(expected, 0, ARRAY_SIZE(expected));
213 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, ARRAY_SIZE(expected));
214 SetLastError(0xdeadbeef);
215 memset(buffer, 0, ARRAY_SIZE(buffer));
216 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, ARRAY_SIZE(buffer));
217 ok((ret == len) && !lstrcmpA(buffer, expected),
218 "got %d with '%s' (expected %d with '%s')\n",
219 ret, buffer, len, expected);
222 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
223 * partially fill the buffer even if it is too short. See bug 637.
225 SetLastError(0xdeadbeef);
226 memset(buffer, 0, ARRAY_SIZE(buffer));
227 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
228 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
230 SetLastError(0xdeadbeef);
231 memset(buffer, 0, ARRAY_SIZE(buffer));
232 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
233 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
234 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
235 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
237 SetLastError(0xdeadbeef);
238 memset(buffer, 0, ARRAY_SIZE(buffer));
239 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
240 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
241 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
244 struct neutralsublang_name2_t {
245 WCHAR name[3];
246 WCHAR sname[15];
247 LCID lcid;
248 LCID lcid_broken;
249 WCHAR sname_broken[15];
250 int todo;
253 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
254 { {'a','r',0}, {'a','r','-','S','A',0},
255 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
256 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
257 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
258 { {'d','e',0}, {'d','e','-','D','E',0},
259 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
260 { {'e','n',0}, {'e','n','-','U','S',0},
261 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
262 { {'e','s',0}, {'e','s','-','E','S',0},
263 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
264 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
265 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
266 { {'g','a',0}, {'g','a','-','I','E',0},
267 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
268 { {'i','t',0}, {'i','t','-','I','T',0},
269 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
270 { {'m','s',0}, {'m','s','-','M','Y',0},
271 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
272 { {'n','l',0}, {'n','l','-','N','L',0},
273 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
274 { {'p','t',0}, {'p','t','-','B','R',0},
275 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
276 { {'s','r',0}, {'h','r','-','H','R',0},
277 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
278 { {'s','v',0}, {'s','v','-','S','E',0},
279 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
280 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
281 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
282 { {'z','h',0}, {'z','h','-','C','N',0},
283 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
284 { {0} }
287 static void test_GetLocaleInfoW(void)
289 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
290 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
291 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
292 WCHAR bufferW[80], buffer2W[80];
293 CHAR bufferA[80];
294 DWORD val;
295 DWORD ret;
296 INT i;
298 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW));
299 if (!ret) {
300 win_skip("GetLocaleInfoW() isn't implemented\n");
301 return;
304 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
305 ok(ret, "got %d\n", ret);
306 ok(val == lcid_en, "got 0x%08x\n", val);
308 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
309 if (ret)
311 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
312 'S','t','a','t','e','s',')',0};
313 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
314 static const WCHAR enW[] = {'e','n','-','U','S',0};
315 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
317 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
319 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW));
320 ok(ret, "got %d\n", ret);
321 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
322 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
324 skip("Non-English locale\n");
326 else
327 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
329 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, ARRAY_SIZE(bufferW));
330 ok(ret, "got %d\n", ret);
331 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
332 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
334 skip("Non-English locale\n");
336 else
337 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
339 while (*ptr->name)
341 LANGID langid;
342 LCID lcid;
344 /* make neutral lcid */
345 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
346 lcid = MAKELCID(langid, SORT_DEFAULT);
348 val = 0;
349 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
350 todo_wine_if (ptr->todo & 0x1)
351 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
352 wine_dbgstr_w(ptr->name), val, ptr->lcid);
354 /* now check LOCALE_SNAME */
355 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
356 todo_wine_if (ptr->todo & 0x2)
357 ok(!lstrcmpW(bufferW, ptr->sname) ||
358 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
359 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
360 ptr++;
363 else
364 win_skip("English neutral locale not supported\n");
366 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, ARRAY_SIZE(bufferW));
367 if (!ret) {
368 win_skip("LANG_RUSSIAN locale data unavailable\n");
369 return;
371 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
372 bufferW, ARRAY_SIZE(bufferW));
373 if (!ret) {
374 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
375 return;
378 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
379 bufferA[0] = 'a';
380 SetLastError(0xdeadbeef);
381 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
382 bufferA, ARRAY_SIZE(bufferA));
383 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
384 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
385 ok(GetLastError() == ERROR_INVALID_FLAGS,
386 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
388 bufferW[0] = 'a';
389 SetLastError(0xdeadbeef);
390 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES, bufferW, ARRAY_SIZE(bufferW));
391 ok(ret == 0,
392 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
393 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
394 ok(GetLastError() == ERROR_INVALID_FLAGS,
395 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
397 /* yes, test empty 13 month entry too */
398 for (i = 0; i < 12; i++) {
399 bufferW[0] = 0;
400 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
401 bufferW, ARRAY_SIZE(bufferW));
402 ok(ret, "Expected non zero result\n");
403 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
404 ret, lstrlenW(bufferW));
405 buffer2W[0] = 0;
406 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W));
407 ok(ret, "Expected non zero result\n");
408 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
409 ret, lstrlenW(buffer2W));
411 ok(lstrcmpW(bufferW, buffer2W) != 0,
412 "Expected genitive name to differ, got the same for month %d\n", i+1);
414 /* for locale without genitive names nominative returned in both cases */
415 bufferW[0] = 0;
416 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
417 bufferW, ARRAY_SIZE(bufferW));
418 ok(ret, "Expected non zero result\n");
419 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
420 ret, lstrlenW(bufferW));
421 buffer2W[0] = 0;
422 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i, buffer2W, ARRAY_SIZE(buffer2W));
423 ok(ret, "Expected non zero result\n");
424 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
425 ret, lstrlenW(buffer2W));
427 ok(lstrcmpW(bufferW, buffer2W) == 0,
428 "Expected same names, got different for month %d\n", i+1);
432 static void test_GetTimeFormatA(void)
434 int ret;
435 SYSTEMTIME curtime;
436 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
437 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
439 memset(&curtime, 2, sizeof(SYSTEMTIME));
440 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
441 SetLastError(0xdeadbeef);
442 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
443 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
444 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
446 curtime.wHour = 8;
447 curtime.wMinute = 56;
448 curtime.wSecond = 13;
449 curtime.wMilliseconds = 22;
450 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
451 SetLastError(0xdeadbeef);
452 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
453 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
454 EXPECT_LENA; EXPECT_EQA;
456 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
457 SetLastError(0xdeadbeef);
458 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
459 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
460 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
462 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
463 SetLastError(0xdeadbeef);
464 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
465 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
466 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
468 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
469 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
470 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
471 EXPECT_LENA;
473 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
474 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
475 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
476 EXPECT_LENA; EXPECT_EQA;
478 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
479 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
480 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
481 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
482 "Expected '', got '%s'\n", buffer );
484 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
485 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
486 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
487 EXPECT_LENA; EXPECT_EQA;
489 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
490 strcpy(Expected, "8:56 AM");
491 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493 EXPECT_LENA; EXPECT_EQA;
495 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
496 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
498 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
499 "Expected '8.@:56AM', got '%s'\n", buffer );
501 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
502 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
503 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
504 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
505 "Expected '', got '%s'\n", buffer );
507 STRINGSA("t/tt", "A/AM"); /* AM time marker */
508 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
509 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
510 EXPECT_LENA; EXPECT_EQA;
512 curtime.wHour = 13;
513 STRINGSA("t/tt", "P/PM"); /* PM time marker */
514 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
515 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
516 EXPECT_LENA; EXPECT_EQA;
518 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
519 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, ARRAY_SIZE(buffer));
520 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
521 EXPECT_LENA; EXPECT_EQA;
523 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
524 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
526 EXPECT_LENA; EXPECT_EQA;
528 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
529 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
531 EXPECT_LENA; EXPECT_EQA;
533 curtime.wHour = 14; /* change this to 14 or 2pm */
534 curtime.wMinute = 5;
535 curtime.wSecond = 3;
536 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 */
537 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
538 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
539 EXPECT_LENA; EXPECT_EQA;
541 curtime.wHour = 0;
542 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
543 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
545 EXPECT_LENA; EXPECT_EQA;
547 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
548 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
549 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
550 EXPECT_LENA; EXPECT_EQA;
552 /* try to convert formatting strings with more than two letters
553 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
554 * NOTE: We expect any letter for which there is an upper case value
555 * we should see a replacement. For letters that DO NOT have
556 * upper case values we should see NO REPLACEMENT.
558 curtime.wHour = 8;
559 curtime.wMinute = 56;
560 curtime.wSecond = 13;
561 curtime.wMilliseconds = 22;
562 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
563 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
564 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
565 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
566 EXPECT_LENA; EXPECT_EQA;
568 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
569 strcpy(buffer, "text");
570 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
571 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
572 EXPECT_EQA;
574 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
575 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
576 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
577 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
578 EXPECT_LENA; EXPECT_EQA;
580 STRINGSA("'''", "'"); /* invalid quoted string */
581 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
582 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
583 EXPECT_LENA; EXPECT_EQA;
585 /* test that msdn suggested single quotation usage works as expected */
586 STRINGSA("''''", "'"); /* single quote mark */
587 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
588 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
589 EXPECT_LENA; EXPECT_EQA;
591 STRINGSA("''HHHHHH", "08"); /* Normal use */
592 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
593 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
594 EXPECT_LENA; EXPECT_EQA;
596 /* and test for normal use of the single quotation mark */
597 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
598 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
599 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
600 EXPECT_LENA; EXPECT_EQA;
602 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
603 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
604 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
605 EXPECT_LENA; EXPECT_EQA;
607 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
608 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, ARRAY_SIZE(buffer));
609 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
610 EXPECT_LENA; EXPECT_EQA;
612 curtime.wHour = 25;
613 STRINGSA("'123'tt", ""); /* Invalid time */
614 SetLastError(0xdeadbeef);
615 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
616 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
617 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
619 curtime.wHour = 12;
620 curtime.wMonth = 60; /* Invalid */
621 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
622 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
623 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
624 EXPECT_LENA; EXPECT_EQA;
627 static void test_GetTimeFormatEx(void)
629 int ret;
630 SYSTEMTIME curtime;
631 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
633 if (!pGetTimeFormatEx)
635 win_skip("GetTimeFormatEx not supported\n");
636 return;
639 memset(&curtime, 2, sizeof(SYSTEMTIME));
640 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
641 SetLastError(0xdeadbeef);
642 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
643 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
644 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
646 curtime.wHour = 8;
647 curtime.wMinute = 56;
648 curtime.wSecond = 13;
649 curtime.wMilliseconds = 22;
650 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
651 SetLastError(0xdeadbeef);
652 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
653 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
654 EXPECT_LENW; EXPECT_EQW;
656 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
657 SetLastError(0xdeadbeef);
658 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
659 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
660 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
662 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
663 SetLastError(0xdeadbeef);
664 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
665 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
666 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
668 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
669 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
670 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
671 EXPECT_LENW;
673 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
674 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
675 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
676 EXPECT_LENW; EXPECT_EQW;
678 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
679 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
680 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
681 EXPECT_LENW; EXPECT_EQW;
683 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
684 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
685 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
686 EXPECT_LENW; EXPECT_EQW;
688 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
689 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
690 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
691 EXPECT_LENW; EXPECT_EQW;
693 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
694 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
695 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
696 EXPECT_LENW; EXPECT_EQW;
698 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
699 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, ARRAY_SIZE(buffer));
700 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
701 EXPECT_LENW; EXPECT_EQW;
703 STRINGSW("t/tt", "A/AM"); /* AM time marker */
704 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
705 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
706 EXPECT_LENW; EXPECT_EQW;
708 curtime.wHour = 13;
709 STRINGSW("t/tt", "P/PM"); /* PM time marker */
710 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
711 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
712 EXPECT_LENW; EXPECT_EQW;
714 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
715 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, ARRAY_SIZE(buffer));
716 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
717 EXPECT_LENW; EXPECT_EQW;
719 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
720 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
721 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
722 EXPECT_LENW; EXPECT_EQW;
724 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
725 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, ARRAY_SIZE(buffer));
726 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
727 EXPECT_LENW; EXPECT_EQW;
729 curtime.wHour = 14; /* change this to 14 or 2pm */
730 curtime.wMinute = 5;
731 curtime.wSecond = 3;
732 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 */
733 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
734 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
735 EXPECT_LENW; EXPECT_EQW;
737 curtime.wHour = 0;
738 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
739 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
740 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
741 EXPECT_LENW; EXPECT_EQW;
743 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
744 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
745 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
746 EXPECT_LENW; EXPECT_EQW;
748 /* try to convert formatting strings with more than two letters
749 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
750 * NOTE: We expect any letter for which there is an upper case value
751 * we should see a replacement. For letters that DO NOT have
752 * upper case values we should see NO REPLACEMENT.
754 curtime.wHour = 8;
755 curtime.wMinute = 56;
756 curtime.wSecond = 13;
757 curtime.wMilliseconds = 22;
758 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
759 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
760 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
761 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
762 EXPECT_LENW; EXPECT_EQW;
764 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
765 lstrcpyW(buffer, Expected);
766 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
767 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
768 EXPECT_EQW;
770 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
771 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
772 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
773 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
774 EXPECT_LENW; EXPECT_EQW;
776 STRINGSW("'''", "'"); /* invalid quoted string */
777 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
778 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
779 EXPECT_LENW; EXPECT_EQW;
781 /* test that msdn suggested single quotation usage works as expected */
782 STRINGSW("''''", "'"); /* single quote mark */
783 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
784 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
785 EXPECT_LENW; EXPECT_EQW;
787 STRINGSW("''HHHHHH", "08"); /* Normal use */
788 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
789 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
790 EXPECT_LENW; EXPECT_EQW;
792 /* and test for normal use of the single quotation mark */
793 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
794 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
795 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
796 EXPECT_LENW; EXPECT_EQW;
798 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
799 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
800 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
801 EXPECT_LENW; EXPECT_EQW;
803 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
804 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, ARRAY_SIZE(buffer));
805 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
806 EXPECT_LENW; EXPECT_EQW;
808 curtime.wHour = 25;
809 STRINGSW("'123'tt", ""); /* Invalid time */
810 SetLastError(0xdeadbeef);
811 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
812 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
813 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
815 curtime.wHour = 12;
816 curtime.wMonth = 60; /* Invalid */
817 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
818 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
819 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
820 EXPECT_LENW; EXPECT_EQW;
823 static void test_GetDateFormatA(void)
825 int ret;
826 SYSTEMTIME curtime;
827 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
828 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
829 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
830 char Broken[BUFFER_SIZE];
831 char short_day[10], month[10], genitive_month[10];
833 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
834 STRINGSA("ddd',' MMM dd yy","");
835 SetLastError(0xdeadbeef);
836 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
837 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
838 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
840 curtime.wYear = 2002;
841 curtime.wMonth = 5;
842 curtime.wDay = 4;
843 curtime.wDayOfWeek = 3;
844 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
845 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
846 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
847 EXPECT_LENA; EXPECT_EQA;
849 /* Same as above but with LOCALE_NOUSEROVERRIDE */
850 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
851 SetLastError(0xdeadbeef);
852 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, ARRAY_SIZE(buffer));
853 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
854 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
855 EXPECT_EQA;
857 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
858 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
859 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
860 EXPECT_LENA; EXPECT_EQA;
862 curtime.wHour = 36; /* Invalid */
863 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
864 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
865 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
866 EXPECT_LENA; EXPECT_EQA;
868 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
869 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
870 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
871 EXPECT_EQA;
873 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
874 SetLastError(0xdeadbeef);
875 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
876 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
877 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
879 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
880 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
881 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
882 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
883 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
885 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
886 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, ARRAY_SIZE(buffer));
887 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
888 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
889 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
890 "got an unexpected date string '%s'\n", buffer);
892 /* test for expected DATE_YEARMONTH behavior with null format */
893 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
894 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
895 SetLastError(0xdeadbeef);
896 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, ARRAY_SIZE(buffer));
897 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
898 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
899 EXPECT_EQA;
901 /* Test that using invalid DATE_* flags results in the correct error */
902 /* and return values */
903 STRINGSA("m/d/y", ""); /* Invalid flags */
904 SetLastError(0xdeadbeef);
905 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, &curtime, input,
906 buffer, ARRAY_SIZE(buffer));
907 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
908 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
910 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, ARRAY_SIZE(buffer));
911 if (!ret)
913 win_skip("LANG_RUSSIAN locale data unavailable\n");
914 return;
917 /* month part should be in genitive form */
918 strcpy(genitive_month, buffer + 2);
919 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, ARRAY_SIZE(buffer));
920 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
921 strcpy(month, buffer);
922 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
924 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, ARRAY_SIZE(buffer));
925 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
926 strcpy(short_day, buffer);
928 STRINGSA("dd MMMMddd dd", "");
929 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
930 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
931 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
932 EXPECT_EQA;
934 STRINGSA("MMMMddd dd", "");
935 sprintf(Expected, "%s%s 04", month, short_day);
936 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
937 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
938 EXPECT_EQA;
940 STRINGSA("MMMMddd", "");
941 sprintf(Expected, "%s%s", month, short_day);
942 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
943 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
944 EXPECT_EQA;
946 STRINGSA("MMMMdd", "");
947 sprintf(Expected, "%s04", genitive_month);
948 sprintf(Broken, "%s04", month);
949 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
950 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
951 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
952 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
953 "Expected '%s', got '%s'\n", Expected, buffer);
955 STRINGSA("MMMMdd ddd", "");
956 sprintf(Expected, "%s04 %s", genitive_month, short_day);
957 sprintf(Broken, "%s04 %s", month, short_day);
958 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
959 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
960 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
961 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
962 "Expected '%s', got '%s'\n", Expected, buffer);
964 STRINGSA("dd dddMMMM", "");
965 sprintf(Expected, "04 %s%s", short_day, month);
966 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
967 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
968 EXPECT_EQA;
970 STRINGSA("dd dddMMMM ddd MMMMdd", "");
971 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
972 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
973 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
974 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
975 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
976 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
977 "Expected '%s', got '%s'\n", Expected, buffer);
979 /* with literal part */
980 STRINGSA("ddd',' MMMM dd", "");
981 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
982 sprintf(Broken, "%s, %s 04", short_day, month);
983 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
984 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
985 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
986 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
987 "Expected '%s', got '%s'\n", Expected, buffer);
990 static void test_GetDateFormatEx(void)
992 int ret;
993 SYSTEMTIME curtime;
994 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
996 if (!pGetDateFormatEx)
998 win_skip("GetDateFormatEx not supported\n");
999 return;
1002 STRINGSW("",""); /* If flags are set, then format must be NULL */
1003 SetLastError(0xdeadbeef);
1004 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL, input, buffer, ARRAY_SIZE(buffer), NULL);
1005 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1006 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1007 EXPECT_EQW;
1009 STRINGSW("",""); /* NULL buffer, len > 0 */
1010 SetLastError(0xdeadbeef);
1011 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, ARRAY_SIZE(buffer), NULL);
1012 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1013 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1015 STRINGSW("",""); /* NULL buffer, len == 0 */
1016 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1017 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1018 EXPECT_LENW; EXPECT_EQW;
1020 STRINGSW("",""); /* Invalid flag combination */
1021 SetLastError(0xdeadbeef);
1022 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1023 input, NULL, 0, NULL);
1024 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1025 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1026 EXPECT_EQW;
1028 curtime.wYear = 2002;
1029 curtime.wMonth = 10;
1030 curtime.wDay = 23;
1031 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1032 curtime.wHour = 65432; /* Invalid */
1033 curtime.wMinute = 34512; /* Invalid */
1034 curtime.wSecond = 65535; /* Invalid */
1035 curtime.wMilliseconds = 12345;
1036 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1037 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer), NULL);
1038 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1039 EXPECT_LENW; EXPECT_EQW;
1041 curtime.wYear = 2002;
1042 curtime.wMonth = 10;
1043 curtime.wDay = 23;
1044 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1045 curtime.wHour = 65432; /* Invalid */
1046 curtime.wMinute = 34512; /* Invalid */
1047 curtime.wSecond = 65535; /* Invalid */
1048 curtime.wMilliseconds = 12345;
1049 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1050 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer), emptyW); /* Use reserved arg */
1051 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1052 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1054 /* Limit tests */
1056 curtime.wYear = 1601;
1057 curtime.wMonth = 1;
1058 curtime.wDay = 1;
1059 curtime.wDayOfWeek = 0; /* Irrelevant */
1060 curtime.wHour = 0;
1061 curtime.wMinute = 0;
1062 curtime.wSecond = 0;
1063 curtime.wMilliseconds = 0;
1064 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1065 SetLastError(0xdeadbeef);
1066 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer), NULL);
1067 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1068 EXPECT_LENW; EXPECT_EQW;
1070 curtime.wYear = 1600;
1071 curtime.wMonth = 12;
1072 curtime.wDay = 31;
1073 curtime.wDayOfWeek = 0; /* Irrelevant */
1074 curtime.wHour = 23;
1075 curtime.wMinute = 59;
1076 curtime.wSecond = 59;
1077 curtime.wMilliseconds = 999;
1078 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1079 SetLastError(0xdeadbeef);
1080 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, ARRAY_SIZE(buffer), NULL);
1081 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1082 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1085 static void test_GetDateFormatW(void)
1087 int ret;
1088 SYSTEMTIME curtime;
1089 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1090 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1092 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1093 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL, input, buffer, ARRAY_SIZE(buffer));
1094 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1096 win_skip("GetDateFormatW is not implemented\n");
1097 return;
1099 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1100 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1101 EXPECT_EQW;
1103 STRINGSW("",""); /* NULL buffer, len > 0 */
1104 SetLastError(0xdeadbeef);
1105 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, ARRAY_SIZE(buffer));
1106 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1107 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1109 STRINGSW("",""); /* NULL buffer, len == 0 */
1110 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1111 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1112 EXPECT_LENW; EXPECT_EQW;
1114 curtime.wYear = 2002;
1115 curtime.wMonth = 10;
1116 curtime.wDay = 23;
1117 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1118 curtime.wHour = 65432; /* Invalid */
1119 curtime.wMinute = 34512; /* Invalid */
1120 curtime.wSecond = 65535; /* Invalid */
1121 curtime.wMilliseconds = 12345;
1122 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1123 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
1124 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1125 EXPECT_LENW; EXPECT_EQW;
1127 /* Limit tests */
1129 curtime.wYear = 1601;
1130 curtime.wMonth = 1;
1131 curtime.wDay = 1;
1132 curtime.wDayOfWeek = 0; /* Irrelevant */
1133 curtime.wHour = 0;
1134 curtime.wMinute = 0;
1135 curtime.wSecond = 0;
1136 curtime.wMilliseconds = 0;
1137 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1138 SetLastError(0xdeadbeef);
1139 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
1140 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1141 EXPECT_LENW; EXPECT_EQW;
1143 curtime.wYear = 1600;
1144 curtime.wMonth = 12;
1145 curtime.wDay = 31;
1146 curtime.wDayOfWeek = 0; /* Irrelevant */
1147 curtime.wHour = 23;
1148 curtime.wMinute = 59;
1149 curtime.wSecond = 59;
1150 curtime.wMilliseconds = 999;
1151 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1152 SetLastError(0xdeadbeef);
1153 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, ARRAY_SIZE(buffer));
1154 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1155 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1159 #define CY_POS_LEFT 0
1160 #define CY_POS_RIGHT 1
1161 #define CY_POS_LEFT_SPACE 2
1162 #define CY_POS_RIGHT_SPACE 3
1164 static void test_GetCurrencyFormatA(void)
1166 static char szDot[] = { '.', '\0' };
1167 static char szComma[] = { ',', '\0' };
1168 static char szDollar[] = { '$', '\0' };
1169 int ret;
1170 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1171 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1172 CURRENCYFMTA format;
1174 memset(&format, 0, sizeof(format));
1176 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1177 SetLastError(0xdeadbeef);
1178 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, ARRAY_SIZE(buffer));
1179 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1180 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1182 STRINGSA("23,53",""); /* Invalid character --> Error */
1183 SetLastError(0xdeadbeef);
1184 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1185 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1186 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1188 STRINGSA("--",""); /* Double '-' --> Error */
1189 SetLastError(0xdeadbeef);
1190 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1191 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1192 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1194 STRINGSA("0-",""); /* Trailing '-' --> Error */
1195 SetLastError(0xdeadbeef);
1196 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1197 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1198 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1200 STRINGSA("0..",""); /* Double '.' --> Error */
1201 SetLastError(0xdeadbeef);
1202 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1203 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1204 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1206 STRINGSA(" 0.1",""); /* Leading space --> Error */
1207 SetLastError(0xdeadbeef);
1208 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1209 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1210 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1212 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1213 SetLastError(0xdeadbeef);
1214 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1215 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1216 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1218 STRINGSA("2353",""); /* Format and flags given --> Error */
1219 SetLastError(0xdeadbeef);
1220 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, ARRAY_SIZE(buffer));
1221 ok( !ret, "Expected ret == 0, got %d\n", ret);
1222 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1223 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1225 STRINGSA("2353",""); /* Invalid format --> Error */
1226 SetLastError(0xdeadbeef);
1227 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1228 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1229 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1231 STRINGSA("2353","$2,353.00"); /* Valid number */
1232 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1233 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1234 EXPECT_LENA; EXPECT_EQA;
1236 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1237 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1238 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1239 EXPECT_LENA; EXPECT_EQA;
1241 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1242 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1243 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1244 EXPECT_LENA; EXPECT_EQA;
1246 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1247 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1248 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1249 EXPECT_LENA; EXPECT_EQA;
1251 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1252 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1253 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1254 EXPECT_LENA; EXPECT_EQA;
1256 format.NumDigits = 0; /* No decimal separator */
1257 format.LeadingZero = 0;
1258 format.Grouping = 0; /* No grouping char */
1259 format.NegativeOrder = 0;
1260 format.PositiveOrder = CY_POS_LEFT;
1261 format.lpDecimalSep = szDot;
1262 format.lpThousandSep = szComma;
1263 format.lpCurrencySymbol = szDollar;
1265 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1266 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1267 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1268 EXPECT_LENA; EXPECT_EQA;
1270 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1271 STRINGSA("2353","$2353.0");
1272 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1273 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1274 EXPECT_LENA; EXPECT_EQA;
1276 format.Grouping = 2; /* Group by 100's */
1277 STRINGSA("2353","$23,53.0");
1278 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1279 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1280 EXPECT_LENA; EXPECT_EQA;
1282 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1283 format.Grouping = 3;
1284 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1285 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1286 EXPECT_LENA; EXPECT_EQA;
1288 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1289 format.NegativeOrder = 2;
1290 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1291 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1292 EXPECT_LENA; EXPECT_EQA;
1294 format.LeadingZero = 1; /* Always provide leading zero */
1295 STRINGSA(".5","$0.5");
1296 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1297 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1298 EXPECT_LENA; EXPECT_EQA;
1300 format.PositiveOrder = CY_POS_RIGHT;
1301 STRINGSA("1","1.0$");
1302 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1303 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1304 EXPECT_LENA; EXPECT_EQA;
1306 format.PositiveOrder = CY_POS_LEFT_SPACE;
1307 STRINGSA("1","$ 1.0");
1308 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1309 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1310 EXPECT_LENA; EXPECT_EQA;
1312 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1313 STRINGSA("1","1.0 $");
1314 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1315 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1316 EXPECT_LENA; EXPECT_EQA;
1318 format.NegativeOrder = 0;
1319 STRINGSA("-1","($1.0)");
1320 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1321 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1322 EXPECT_LENA; EXPECT_EQA;
1324 format.NegativeOrder = 1;
1325 STRINGSA("-1","-$1.0");
1326 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1327 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1328 EXPECT_LENA; EXPECT_EQA;
1330 format.NegativeOrder = 2;
1331 STRINGSA("-1","$-1.0");
1332 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1333 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1334 EXPECT_LENA; EXPECT_EQA;
1336 format.NegativeOrder = 3;
1337 STRINGSA("-1","$1.0-");
1338 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1339 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1340 EXPECT_LENA; EXPECT_EQA;
1342 format.NegativeOrder = 4;
1343 STRINGSA("-1","(1.0$)");
1344 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1345 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1346 EXPECT_LENA; EXPECT_EQA;
1348 format.NegativeOrder = 5;
1349 STRINGSA("-1","-1.0$");
1350 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1351 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1352 EXPECT_LENA; EXPECT_EQA;
1354 format.NegativeOrder = 6;
1355 STRINGSA("-1","1.0-$");
1356 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1357 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1358 EXPECT_LENA; EXPECT_EQA;
1360 format.NegativeOrder = 7;
1361 STRINGSA("-1","1.0$-");
1362 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1363 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1364 EXPECT_LENA; EXPECT_EQA;
1366 format.NegativeOrder = 8;
1367 STRINGSA("-1","-1.0 $");
1368 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1369 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1370 EXPECT_LENA; EXPECT_EQA;
1372 format.NegativeOrder = 9;
1373 STRINGSA("-1","-$ 1.0");
1374 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1375 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1376 EXPECT_LENA; EXPECT_EQA;
1378 format.NegativeOrder = 10;
1379 STRINGSA("-1","1.0 $-");
1380 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1381 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1382 EXPECT_LENA; EXPECT_EQA;
1384 format.NegativeOrder = 11;
1385 STRINGSA("-1","$ 1.0-");
1386 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1387 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1388 EXPECT_LENA; EXPECT_EQA;
1390 format.NegativeOrder = 12;
1391 STRINGSA("-1","$ -1.0");
1392 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1393 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1394 EXPECT_LENA; EXPECT_EQA;
1396 format.NegativeOrder = 13;
1397 STRINGSA("-1","1.0- $");
1398 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1399 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1400 EXPECT_LENA; EXPECT_EQA;
1402 format.NegativeOrder = 14;
1403 STRINGSA("-1","($ 1.0)");
1404 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1405 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1406 EXPECT_LENA; EXPECT_EQA;
1408 format.NegativeOrder = 15;
1409 STRINGSA("-1","(1.0 $)");
1410 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1411 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1412 EXPECT_LENA; EXPECT_EQA;
1415 #define NEG_PARENS 0 /* "(1.1)" */
1416 #define NEG_LEFT 1 /* "-1.1" */
1417 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1418 #define NEG_RIGHT 3 /* "1.1-" */
1419 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1421 static void test_GetNumberFormatA(void)
1423 static char szDot[] = { '.', '\0' };
1424 static char szComma[] = { ',', '\0' };
1425 int ret;
1426 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1427 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1428 NUMBERFMTA format;
1430 memset(&format, 0, sizeof(format));
1432 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1433 SetLastError(0xdeadbeef);
1434 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, ARRAY_SIZE(buffer));
1435 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1436 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1438 STRINGSA("23,53",""); /* Invalid character --> Error */
1439 SetLastError(0xdeadbeef);
1440 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1441 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1442 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1444 STRINGSA("--",""); /* Double '-' --> Error */
1445 SetLastError(0xdeadbeef);
1446 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1447 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1448 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1450 STRINGSA("0-",""); /* Trailing '-' --> Error */
1451 SetLastError(0xdeadbeef);
1452 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1453 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1454 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1456 STRINGSA("0..",""); /* Double '.' --> Error */
1457 SetLastError(0xdeadbeef);
1458 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1459 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1460 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1462 STRINGSA(" 0.1",""); /* Leading space --> Error */
1463 SetLastError(0xdeadbeef);
1464 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1465 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1466 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1468 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1469 SetLastError(0xdeadbeef);
1470 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1471 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1472 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1474 STRINGSA("2353",""); /* Format and flags given --> Error */
1475 SetLastError(0xdeadbeef);
1476 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, ARRAY_SIZE(buffer));
1477 ok( !ret, "Expected ret == 0, got %d\n", ret);
1478 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1479 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1481 STRINGSA("2353",""); /* Invalid format --> Error */
1482 SetLastError(0xdeadbeef);
1483 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1484 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1485 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1487 STRINGSA("2353","2,353.00"); /* Valid number */
1488 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1489 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1490 EXPECT_LENA; EXPECT_EQA;
1492 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1493 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1494 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1495 EXPECT_LENA; EXPECT_EQA;
1497 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1498 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1499 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1500 EXPECT_LENA; EXPECT_EQA;
1502 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1503 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1504 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1505 EXPECT_LENA; EXPECT_EQA;
1507 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1508 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1509 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1510 EXPECT_LENA; EXPECT_EQA;
1512 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1513 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1514 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1515 EXPECT_LENA; EXPECT_EQA;
1517 format.NumDigits = 0; /* No decimal separator */
1518 format.LeadingZero = 0;
1519 format.Grouping = 0; /* No grouping char */
1520 format.NegativeOrder = 0;
1521 format.lpDecimalSep = szDot;
1522 format.lpThousandSep = szComma;
1524 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1525 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1527 EXPECT_LENA; EXPECT_EQA;
1529 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1530 STRINGSA("2353","2353.0");
1531 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1532 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1533 EXPECT_LENA; EXPECT_EQA;
1535 format.Grouping = 2; /* Group by 100's */
1536 STRINGSA("2353","23,53.0");
1537 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1538 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1539 EXPECT_LENA; EXPECT_EQA;
1541 STRINGSA("235","235.0"); /* Grouping of a positive number */
1542 format.Grouping = 3;
1543 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1545 EXPECT_LENA; EXPECT_EQA;
1547 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1548 format.NegativeOrder = NEG_LEFT;
1549 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1550 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1551 EXPECT_LENA; EXPECT_EQA;
1553 format.LeadingZero = 1; /* Always provide leading zero */
1554 STRINGSA(".5","0.5");
1555 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1556 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1557 EXPECT_LENA; EXPECT_EQA;
1559 format.NegativeOrder = NEG_PARENS;
1560 STRINGSA("-1","(1.0)");
1561 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1562 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1563 EXPECT_LENA; EXPECT_EQA;
1565 format.NegativeOrder = NEG_LEFT;
1566 STRINGSA("-1","-1.0");
1567 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1568 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1569 EXPECT_LENA; EXPECT_EQA;
1571 format.NegativeOrder = NEG_LEFT_SPACE;
1572 STRINGSA("-1","- 1.0");
1573 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1574 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1575 EXPECT_LENA; EXPECT_EQA;
1577 format.NegativeOrder = NEG_RIGHT;
1578 STRINGSA("-1","1.0-");
1579 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1580 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1581 EXPECT_LENA; EXPECT_EQA;
1583 format.NegativeOrder = NEG_RIGHT_SPACE;
1584 STRINGSA("-1","1.0 -");
1585 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1586 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1587 EXPECT_LENA; EXPECT_EQA;
1589 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1591 if (IsValidLocale(lcid, 0))
1593 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1594 Expected[3] = 160; /* Non breaking space */
1595 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1596 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1597 EXPECT_LENA; EXPECT_EQA;
1601 static void test_GetNumberFormatEx(void)
1603 int ret;
1604 NUMBERFMTW format;
1605 static WCHAR dotW[] = {'.',0};
1606 static WCHAR commaW[] = {',',0};
1607 static const WCHAR enW[] = {'e','n','-','U','S',0};
1608 static const WCHAR frW[] = {'f','r','-','F','R',0};
1609 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1610 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1612 if (!pGetNumberFormatEx)
1614 win_skip("GetNumberFormatEx is not available.\n");
1615 return;
1618 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1619 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, ARRAY_SIZE(buffer));
1620 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1621 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1623 STRINGSW("23,53",""); /* Invalid character --> Error */
1624 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1625 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1626 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1628 STRINGSW("--",""); /* Double '-' --> Error */
1629 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1630 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1631 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1633 STRINGSW("0-",""); /* Trailing '-' --> Error */
1634 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1635 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1636 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1638 STRINGSW("0..",""); /* Double '.' --> Error */
1639 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1640 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1641 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1643 STRINGSW(" 0.1",""); /* Leading space --> Error */
1644 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, ARRAY_SIZE(buffer));
1645 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1646 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1648 STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1649 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1650 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1651 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1653 STRINGSW("23",""); /* Bogus locale --> Error */
1654 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1655 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1656 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1658 memset(&format, 0, sizeof(format));
1660 STRINGSW("2353",""); /* Format and flags given --> Error */
1661 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, ARRAY_SIZE(buffer));
1662 ok( !ret, "Expected ret == 0, got %d\n", ret);
1663 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1664 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1666 STRINGSW("2353",""); /* Invalid format --> Error */
1667 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1668 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1669 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1671 STRINGSW("2353","2,353.00"); /* Valid number */
1672 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1673 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1674 EXPECT_LENW; EXPECT_EQW;
1676 STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1677 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1678 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1679 EXPECT_LENW; EXPECT_EQW;
1681 STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1682 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1683 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1684 EXPECT_LENW; EXPECT_EQW;
1686 STRINGSW("2353.1","2,353.10"); /* Valid real number */
1687 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1688 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1689 EXPECT_LENW; EXPECT_EQW;
1691 STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1692 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1693 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1694 EXPECT_LENW; EXPECT_EQW;
1696 STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */
1697 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1698 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1699 EXPECT_LENW; EXPECT_EQW;
1701 format.NumDigits = 0; /* No decimal separator */
1702 format.LeadingZero = 0;
1703 format.Grouping = 0; /* No grouping char */
1704 format.NegativeOrder = 0;
1705 format.lpDecimalSep = dotW;
1706 format.lpThousandSep = commaW;
1708 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1709 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1710 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1711 EXPECT_LENW; EXPECT_EQW;
1713 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1714 STRINGSW("2353","2353.0");
1715 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1716 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1717 EXPECT_LENW; EXPECT_EQW;
1719 format.Grouping = 2; /* Group by 100's */
1720 STRINGSW("2353","23,53.0");
1721 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1722 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1723 EXPECT_LENW; EXPECT_EQW;
1725 STRINGSW("235","235.0"); /* Grouping of a positive number */
1726 format.Grouping = 3;
1727 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1728 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1729 EXPECT_LENW; EXPECT_EQW;
1731 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1732 format.NegativeOrder = NEG_LEFT;
1733 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1734 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1735 EXPECT_LENW; EXPECT_EQW;
1737 format.LeadingZero = 1; /* Always provide leading zero */
1738 STRINGSW(".5","0.5");
1739 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1740 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1741 EXPECT_LENW; EXPECT_EQW;
1743 format.NegativeOrder = NEG_PARENS;
1744 STRINGSW("-1","(1.0)");
1745 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1746 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1747 EXPECT_LENW; EXPECT_EQW;
1749 format.NegativeOrder = NEG_LEFT;
1750 STRINGSW("-1","-1.0");
1751 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1752 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1753 EXPECT_LENW; EXPECT_EQW;
1755 format.NegativeOrder = NEG_LEFT_SPACE;
1756 STRINGSW("-1","- 1.0");
1757 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1758 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1759 EXPECT_LENW; EXPECT_EQW;
1761 format.NegativeOrder = NEG_RIGHT;
1762 STRINGSW("-1","1.0-");
1763 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1764 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1765 EXPECT_LENW; EXPECT_EQW;
1767 format.NegativeOrder = NEG_RIGHT_SPACE;
1768 STRINGSW("-1","1.0 -");
1769 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, ARRAY_SIZE(buffer));
1770 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1771 EXPECT_LENW; EXPECT_EQW;
1773 if (pIsValidLocaleName(frW))
1775 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1776 Expected[3] = 160; /* Non breaking space */
1777 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, ARRAY_SIZE(buffer));
1778 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1779 EXPECT_LENW; EXPECT_EQW;
1783 struct comparestringa_entry {
1784 LCID lcid;
1785 DWORD flags;
1786 const char *first;
1787 int first_len;
1788 const char *second;
1789 int second_len;
1790 int ret;
1793 static const struct comparestringa_entry comparestringa_data[] = {
1794 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1797 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1798 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1799 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1808 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1809 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1810 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1811 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1812 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1813 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1814 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1818 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1820 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1821 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1823 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1824 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1825 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1826 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1827 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1828 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1833 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1834 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1835 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1836 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1837 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1840 static void test_CompareStringA(void)
1842 static const char ABC_EE[] = {'A','B','C',0,0xEE};
1843 static const char ABC_FF[] = {'A','B','C',0,0xFF};
1844 int ret, i;
1845 char a[256];
1846 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1848 for (i = 0; i < ARRAY_SIZE(comparestringa_data); i++)
1850 const struct comparestringa_entry *entry = &comparestringa_data[i];
1852 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1853 entry->second, entry->second_len);
1854 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1857 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1858 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1860 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1861 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1863 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1864 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1866 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1867 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1869 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1871 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1872 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1874 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1875 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1877 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1878 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1880 /* test for CompareStringA flags */
1881 SetLastError(0xdeadbeef);
1882 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1883 ok(GetLastError() == ERROR_INVALID_FLAGS,
1884 "unexpected error code %d\n", GetLastError());
1885 ok(!ret, "CompareStringA must fail with invalid flag\n");
1887 SetLastError(0xdeadbeef);
1888 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1889 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1890 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1891 /* end of test for CompareStringA flags */
1893 ret = lstrcmpA("", "");
1894 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1896 ret = lstrcmpA(NULL, NULL);
1897 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1899 ret = lstrcmpA("", NULL);
1900 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1902 ret = lstrcmpA(NULL, "");
1903 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1906 if (0) { /* this requires collation table patch to make it MS compatible */
1907 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1908 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1910 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1911 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1913 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1914 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1916 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1917 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1919 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1920 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1922 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1923 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1925 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1926 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1928 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1929 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1931 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1932 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1934 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1935 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1937 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1938 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1940 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1941 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1945 /* WinXP handles embedded NULLs differently than earlier versions */
1946 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1947 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1949 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1950 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);
1952 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1953 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1955 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1956 ok(ret == CSTR_EQUAL || /* win2k */
1957 ret == CSTR_GREATER_THAN,
1958 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1960 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1961 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1963 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1964 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1966 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1967 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1969 ret = lstrcmpiA("#", ".");
1970 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1972 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1974 /* \xB9 character lies between a and b */
1975 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1976 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1977 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1978 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1980 memset(a, 'a', sizeof(a));
1981 SetLastError(0xdeadbeef);
1982 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1983 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1984 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1986 ret = CompareStringA(CP_ACP, 0, ABC_EE, 3, ABC_FF, 3);
1987 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
1988 ret = CompareStringA(CP_ACP, 0, ABC_EE, 5, ABC_FF, 3);
1989 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
1990 ret = CompareStringA(CP_ACP, 0, ABC_EE, 3, ABC_FF, 5);
1991 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
1992 ret = CompareStringA(CP_ACP, 0, ABC_EE, 5, ABC_FF, 5);
1993 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
1994 ret = CompareStringA(CP_ACP, 0, ABC_FF, 5, ABC_EE, 5);
1995 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
1998 static void test_CompareStringW(void)
2000 static const WCHAR ABC_EE[] = {'A','B','C',0,0xEE};
2001 static const WCHAR ABC_FF[] = {'A','B','C',0,0xFF};
2002 WCHAR *str1, *str2;
2003 SYSTEM_INFO si;
2004 DWORD old_prot;
2005 BOOL success;
2006 char *buf;
2007 int ret;
2009 GetSystemInfo(&si);
2010 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
2011 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
2012 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2013 ok(success, "VirtualProtect failed with %u\n", GetLastError());
2014 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2015 ok(success, "VirtualProtect failed with %u\n", GetLastError());
2017 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2018 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2019 *str1 = 'A';
2020 *str2 = 'B';
2022 /* CompareStringW should abort on the first non-matching character */
2023 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2024 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2026 success = VirtualFree(buf, 0, MEM_RELEASE);
2027 ok(success, "VirtualFree failed with %u\n", GetLastError());
2029 ret = CompareStringW(CP_ACP, 0, ABC_EE, 3, ABC_FF, 3);
2030 ok(ret == CSTR_EQUAL, "expected CSTR_EQUAL, got %d\n", ret);
2031 ret = CompareStringW(CP_ACP, 0, ABC_EE, 5, ABC_FF, 3);
2032 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
2033 ret = CompareStringW(CP_ACP, 0, ABC_EE, 3, ABC_FF, 5);
2034 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2035 ret = CompareStringW(CP_ACP, 0, ABC_EE, 5, ABC_FF, 5);
2036 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2037 ret = CompareStringW(CP_ACP, 0, ABC_FF, 5, ABC_EE, 5);
2038 ok(ret == CSTR_GREATER_THAN, "expected CSTR_GREATER_THAN, got %d\n", ret);
2041 struct comparestringex_test {
2042 const char *locale;
2043 DWORD flags;
2044 const WCHAR first[2];
2045 const WCHAR second[2];
2046 INT ret;
2047 INT broken;
2048 BOOL todo;
2051 static const struct comparestringex_test comparestringex_tests[] = {
2052 /* default behavior */
2053 { /* 0 */
2054 "tr-TR", 0,
2055 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2057 { /* 1 */
2058 "tr-TR", 0,
2059 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2061 { /* 2 */
2062 "tr-TR", 0,
2063 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2065 { /* 3 */
2066 "tr-TR", 0,
2067 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2069 { /* 4 */
2070 "tr-TR", 0,
2071 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2073 { /* 5 */
2074 "tr-TR", 0,
2075 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2077 /* with NORM_IGNORECASE */
2078 { /* 6 */
2079 "tr-TR", NORM_IGNORECASE,
2080 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2082 { /* 7 */
2083 "tr-TR", NORM_IGNORECASE,
2084 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2086 { /* 8 */
2087 "tr-TR", NORM_IGNORECASE,
2088 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2090 { /* 9 */
2091 "tr-TR", NORM_IGNORECASE,
2092 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2094 { /* 10 */
2095 "tr-TR", NORM_IGNORECASE,
2096 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2098 { /* 11 */
2099 "tr-TR", NORM_IGNORECASE,
2100 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2102 /* with NORM_LINGUISTIC_CASING */
2103 { /* 12 */
2104 "tr-TR", NORM_LINGUISTIC_CASING,
2105 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2107 { /* 13 */
2108 "tr-TR", NORM_LINGUISTIC_CASING,
2109 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2111 { /* 14 */
2112 "tr-TR", NORM_LINGUISTIC_CASING,
2113 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2115 { /* 15 */
2116 "tr-TR", NORM_LINGUISTIC_CASING,
2117 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2119 { /* 16 */
2120 "tr-TR", NORM_LINGUISTIC_CASING,
2121 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2123 { /* 17 */
2124 "tr-TR", NORM_LINGUISTIC_CASING,
2125 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2127 /* with LINGUISTIC_IGNORECASE */
2128 { /* 18 */
2129 "tr-TR", LINGUISTIC_IGNORECASE,
2130 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2132 { /* 19 */
2133 "tr-TR", LINGUISTIC_IGNORECASE,
2134 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2136 { /* 20 */
2137 "tr-TR", LINGUISTIC_IGNORECASE,
2138 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2140 { /* 21 */
2141 "tr-TR", LINGUISTIC_IGNORECASE,
2142 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2144 { /* 22 */
2145 "tr-TR", LINGUISTIC_IGNORECASE,
2146 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2148 { /* 23 */
2149 "tr-TR", LINGUISTIC_IGNORECASE,
2150 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2152 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2153 { /* 24 */
2154 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2155 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2157 { /* 25 */
2158 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2159 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2161 { /* 26 */
2162 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2163 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2165 { /* 27 */
2166 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2167 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2169 { /* 28 */
2170 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2171 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2173 { /* 29 */
2174 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2175 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2177 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2178 { /* 30 */
2179 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2180 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2182 { /* 31 */
2183 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2184 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2186 { /* 32 */
2187 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2188 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2190 { /* 33 */
2191 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2192 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2194 { /* 34 */
2195 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2196 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2198 { /* 35 */
2199 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2200 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2204 static void test_CompareStringEx(void)
2206 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2207 WCHAR locale[6];
2208 INT ret, i;
2210 /* CompareStringEx is only available on Vista+ */
2211 if (!pCompareStringEx)
2213 win_skip("CompareStringEx not supported\n");
2214 return;
2217 for (i = 0; i < ARRAY_SIZE(comparestringex_tests); i++)
2219 const struct comparestringex_test *e = &comparestringex_tests[i];
2221 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, ARRAY_SIZE(locale));
2222 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2223 todo_wine_if (e->todo)
2224 ok(ret == e->ret || broken(ret == e->broken),
2225 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2230 static const DWORD lcmap_invalid_flags[] = {
2232 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2233 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2234 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2235 LCMAP_LOWERCASE | SORT_STRINGSORT,
2236 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2237 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2238 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2239 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2240 LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2241 LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2242 LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2243 LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2244 LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2245 LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2246 LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2247 LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2248 LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2249 LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2250 LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2251 LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2252 LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2253 LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2254 LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2255 LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2258 static void test_LCMapStringA(void)
2260 int ret, ret2, i;
2261 char buf[256], buf2[256];
2262 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2263 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2264 static const char symbols_stripped[] = "justateststring1";
2266 SetLastError(0xdeadbeef);
2267 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2268 lower_case, -1, buf, sizeof(buf));
2269 ok(ret == lstrlenA(lower_case) + 1,
2270 "ret %d, error %d, expected value %d\n",
2271 ret, GetLastError(), lstrlenA(lower_case) + 1);
2272 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2274 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2275 upper_case, -1, buf, sizeof(buf));
2276 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2277 ok(GetLastError() == ERROR_INVALID_FLAGS,
2278 "unexpected error code %d\n", GetLastError());
2280 /* test invalid flag combinations */
2281 for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) {
2282 lstrcpyA(buf, "foo");
2283 SetLastError(0xdeadbeef);
2284 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2285 lower_case, -1, buf, sizeof(buf));
2286 ok(GetLastError() == ERROR_INVALID_FLAGS,
2287 "LCMapStringA (flag %08x) unexpected error code %d\n",
2288 lcmap_invalid_flags[i], GetLastError());
2289 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2290 lcmap_invalid_flags[i], ret);
2293 /* test LCMAP_LOWERCASE */
2294 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2295 upper_case, -1, buf, sizeof(buf));
2296 ok(ret == lstrlenA(upper_case) + 1,
2297 "ret %d, error %d, expected value %d\n",
2298 ret, GetLastError(), lstrlenA(upper_case) + 1);
2299 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2301 /* test LCMAP_UPPERCASE */
2302 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2303 lower_case, -1, buf, sizeof(buf));
2304 ok(ret == lstrlenA(lower_case) + 1,
2305 "ret %d, error %d, expected value %d\n",
2306 ret, GetLastError(), lstrlenA(lower_case) + 1);
2307 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2309 /* test buffer overflow */
2310 SetLastError(0xdeadbeef);
2311 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2312 lower_case, -1, buf, 4);
2313 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2314 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2316 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2317 lstrcpyA(buf, lower_case);
2318 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2319 buf, -1, buf, sizeof(buf));
2320 if (!ret) /* Win9x */
2321 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2322 else
2324 ok(ret == lstrlenA(lower_case) + 1,
2325 "ret %d, error %d, expected value %d\n",
2326 ret, GetLastError(), lstrlenA(lower_case) + 1);
2327 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2329 lstrcpyA(buf, upper_case);
2330 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2331 buf, -1, buf, sizeof(buf));
2332 if (!ret) /* Win9x */
2333 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2334 else
2336 ok(ret == lstrlenA(upper_case) + 1,
2337 "ret %d, error %d, expected value %d\n",
2338 ret, GetLastError(), lstrlenA(lower_case) + 1);
2339 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2342 /* otherwise src == dst should fail */
2343 SetLastError(0xdeadbeef);
2344 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2345 buf, 10, buf, sizeof(buf));
2346 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2347 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2348 "unexpected error code %d\n", GetLastError());
2349 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2351 /* test whether '\0' is always appended */
2352 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2353 upper_case, -1, buf, sizeof(buf));
2354 ok(ret, "LCMapStringA must succeed\n");
2355 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2356 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2357 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2358 ok(ret2, "LCMapStringA must succeed\n");
2359 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2360 ok(ret == ret2, "lengths of sort keys must be equal\n");
2361 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2363 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2364 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2365 upper_case, -1, buf, sizeof(buf));
2366 ok(ret, "LCMapStringA must succeed\n");
2367 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2368 lower_case, -1, buf2, sizeof(buf2));
2369 ok(ret2, "LCMapStringA must succeed\n");
2370 ok(ret == ret2, "lengths of sort keys must be equal\n");
2371 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2373 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2374 results from plain LCMAP_SORTKEY on Vista */
2376 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2377 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2378 lower_case, -1, buf, sizeof(buf));
2379 ok(ret, "LCMapStringA must succeed\n");
2380 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2381 symbols_stripped, -1, buf2, sizeof(buf2));
2382 ok(ret2, "LCMapStringA must succeed\n");
2383 ok(ret == ret2, "lengths of sort keys must be equal\n");
2384 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2386 /* test NORM_IGNORENONSPACE */
2387 lstrcpyA(buf, "foo");
2388 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2389 lower_case, -1, buf, sizeof(buf));
2390 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2391 lstrlenA(lower_case) + 1, ret);
2392 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2394 /* test NORM_IGNORESYMBOLS */
2395 lstrcpyA(buf, "foo");
2396 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2397 lower_case, -1, buf, sizeof(buf));
2398 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2399 lstrlenA(symbols_stripped) + 1, ret);
2400 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2402 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2403 lstrcpyA(buf, "foo");
2404 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2405 lower_case, -1, buf, sizeof(buf));
2406 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2407 lstrlenA(symbols_stripped) + 1, ret);
2408 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2410 /* test srclen = 0 */
2411 SetLastError(0xdeadbeef);
2412 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2413 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2414 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2415 "unexpected error code %d\n", GetLastError());
2418 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2420 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2422 const static WCHAR japanese_text[] = {
2423 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2424 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2425 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2427 const static WCHAR hiragana_text[] = {
2428 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f, 0x3068,
2429 0x30fc, 0x3094, 0x3049, 0x306e, 0x91ce, 0x539f, 0x306f, 0x5e83,
2430 0x3044, 0x3093, 0x3060, 0x3088, 0x3002, 0
2432 const static WCHAR katakana_text[] = {
2433 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf, 0x30c8,
2434 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x91ce, 0x539f, 0x30cf, 0x5e83,
2435 0x30a4, 0x30f3, 0x30c0, 0x30e8, 0x3002, 0
2437 const static WCHAR halfwidth_text[] = {
2438 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2439 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x91ce, 0x539f, 0x306f,
2440 0x5e83, 0x3044, 0x3093, 0x3060, 0x3088, 0xff61, 0
2442 const static WCHAR halfwidth_text2[] = {
2443 0xff72, 0x30fd, 0xff94, 0xff64, 0xff72, 0xff70, 0xff8a, 0xff84,
2444 0xff70, 0xff73, 0xff9e, 0xff6b, 0xff89, 0x91ce, 0x539f, 0xff8a,
2445 0x5e83, 0xff72, 0xff9d, 0xff80, 0xff9e, 0xff96, 0xff61, 0
2447 int ret, ret2, i;
2448 WCHAR buf[256], buf2[256];
2449 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2451 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2452 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE, lower_case, -1, buf, ARRAY_SIZE(buf));
2453 todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2454 "%s ret %d, error %d, expected value %d\n", func_name,
2455 ret, GetLastError(), lstrlenW(title_case) + 1);
2456 todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2457 "Expected title case string\n");
2459 /* test invalid flag combinations */
2460 for (i = 0; i < ARRAY_SIZE(lcmap_invalid_flags); i++) {
2461 lstrcpyW(buf, fooW);
2462 SetLastError(0xdeadbeef);
2463 ret = func_ptr(lcmap_invalid_flags[i],
2464 lower_case, -1, buf, sizeof(buf));
2465 ok(GetLastError() == ERROR_INVALID_FLAGS,
2466 "%s (flag %08x) unexpected error code %d\n",
2467 func_name, lcmap_invalid_flags[i], GetLastError());
2468 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2469 func_name, lcmap_invalid_flags[i], ret);
2472 /* test LCMAP_LOWERCASE */
2473 ret = func_ptr(LCMAP_LOWERCASE, upper_case, -1, buf, ARRAY_SIZE(buf));
2474 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2475 ret, GetLastError(), lstrlenW(upper_case) + 1);
2476 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2478 /* test LCMAP_UPPERCASE */
2479 ret = func_ptr(LCMAP_UPPERCASE, lower_case, -1, buf, ARRAY_SIZE(buf));
2480 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2481 ret, GetLastError(), lstrlenW(lower_case) + 1);
2482 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2484 /* test LCMAP_HIRAGANA */
2485 ret = func_ptr(LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf));
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 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2491 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2492 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2493 ret, GetLastError());
2494 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2495 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2496 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2498 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2499 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE, japanese_text, -1, buf, ARRAY_SIZE(buf));
2500 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2501 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2502 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2504 /* test LCMAP_FULLWIDTH */
2505 ret = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, buf, ARRAY_SIZE(buf));
2506 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2507 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2508 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2510 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2511 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2513 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2514 (half-width katakana is converted into full-width hiragana) */
2515 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, buf, ARRAY_SIZE(buf));
2516 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2517 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2518 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2520 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2521 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2523 /* test LCMAP_HALFWIDTH */
2524 ret = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, buf, ARRAY_SIZE(buf));
2525 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2526 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2527 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2529 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2530 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2532 /* test LCMAP_HALFWIDTH | LCMAP_KATAKANA
2533 (hiragana character is converted into half-width katakana) */
2534 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, buf, ARRAY_SIZE(buf));
2535 ok(ret == lstrlenW(halfwidth_text2) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2536 ret, GetLastError(), lstrlenW(halfwidth_text2) + 1);
2537 ok(!lstrcmpW(buf, halfwidth_text2), "%s string compare mismatch\n", func_name);
2539 ret2 = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, NULL, 0);
2540 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2542 /* test buffer overflow */
2543 SetLastError(0xdeadbeef);
2544 ret = func_ptr(LCMAP_UPPERCASE,
2545 lower_case, -1, buf, 4);
2546 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2547 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2549 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2550 Thus, it requires two WCHARs. */
2551 buf[0] = 0x30ac;
2552 SetLastError(0xdeadbeef);
2553 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2554 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2555 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2557 buf[0] = 'a';
2558 buf[1] = 0x30ac;
2559 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 0);
2560 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2562 SetLastError(0xdeadbeef);
2563 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 1);
2564 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2565 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2567 SetLastError(0xdeadbeef);
2568 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 2);
2569 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2570 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2572 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 3);
2573 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2575 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_UPPERCASE, buf, 2, buf2, 4);
2576 ok(ret == 3, "%s ret %d, expected value 3\n", func_name, ret);
2578 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2579 lstrcpyW(buf, lower_case);
2580 ret = func_ptr(LCMAP_UPPERCASE, buf, -1, buf, ARRAY_SIZE(buf));
2581 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2582 ret, GetLastError(), lstrlenW(lower_case) + 1);
2583 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2585 lstrcpyW(buf, upper_case);
2586 ret = func_ptr(LCMAP_LOWERCASE, buf, -1, buf, ARRAY_SIZE(buf));
2587 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2588 ret, GetLastError(), lstrlenW(lower_case) + 1);
2589 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2591 /* otherwise src == dst should fail */
2592 SetLastError(0xdeadbeef);
2593 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2594 buf, 10, buf, sizeof(buf));
2595 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2596 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2597 "%s unexpected error code %d\n", func_name, GetLastError());
2598 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2600 /* test whether '\0' is always appended */
2601 ret = func_ptr(LCMAP_SORTKEY,
2602 upper_case, -1, buf, sizeof(buf));
2603 ok(ret, "%s func_ptr must succeed\n", func_name);
2604 ret2 = func_ptr(LCMAP_SORTKEY,
2605 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2606 ok(ret, "%s func_ptr must succeed\n", func_name);
2607 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2608 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2610 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2611 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2612 upper_case, -1, buf, sizeof(buf));
2613 ok(ret, "%s func_ptr must succeed\n", func_name);
2614 ret2 = func_ptr(LCMAP_SORTKEY,
2615 lower_case, -1, buf2, sizeof(buf2));
2616 ok(ret2, "%s func_ptr must succeed\n", func_name);
2617 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2618 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2620 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2621 results from plain LCMAP_SORTKEY on Vista */
2623 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2624 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2625 lower_case, -1, buf, sizeof(buf));
2626 ok(ret, "%s func_ptr must succeed\n", func_name);
2627 ret2 = func_ptr(LCMAP_SORTKEY,
2628 symbols_stripped, -1, buf2, sizeof(buf2));
2629 ok(ret2, "%s func_ptr must succeed\n", func_name);
2630 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2631 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2633 /* test NORM_IGNORENONSPACE */
2634 lstrcpyW(buf, fooW);
2635 ret = func_ptr(NORM_IGNORENONSPACE, lower_case, -1, buf, ARRAY_SIZE(buf));
2636 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2637 lstrlenW(lower_case) + 1, ret);
2638 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2640 /* test NORM_IGNORESYMBOLS */
2641 lstrcpyW(buf, fooW);
2642 ret = func_ptr(NORM_IGNORESYMBOLS, lower_case, -1, buf, ARRAY_SIZE(buf));
2643 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2644 lstrlenW(symbols_stripped) + 1, ret);
2645 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2647 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2648 lstrcpyW(buf, fooW);
2649 ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE, lower_case, -1, buf, ARRAY_SIZE(buf));
2650 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2651 lstrlenW(symbols_stripped) + 1, ret);
2652 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2654 /* test srclen = 0 */
2655 SetLastError(0xdeadbeef);
2656 ret = func_ptr(0, upper_case, 0, buf, ARRAY_SIZE(buf));
2657 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2658 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2659 "%s unexpected error code %d\n", func_name, GetLastError());
2662 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2664 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2667 static void test_LCMapStringW(void)
2669 int ret;
2670 WCHAR buf[256];
2672 trace("testing LCMapStringW\n");
2674 SetLastError(0xdeadbeef);
2675 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, ARRAY_SIZE(buf));
2676 todo_wine {
2677 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2678 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2681 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2684 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2686 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2689 static void test_LCMapStringEx(void)
2691 int ret;
2692 WCHAR buf[256];
2694 if (!pLCMapStringEx)
2696 win_skip( "LCMapStringEx not available\n" );
2697 return;
2700 trace("testing LCMapStringEx\n");
2702 SetLastError(0xdeadbeef);
2703 ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2704 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 0);
2705 todo_wine {
2706 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2707 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2710 /* test reserved parameters */
2711 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2712 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, NULL, 1);
2713 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2714 ret, GetLastError(), lstrlenW(upper_case) + 1);
2715 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2717 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2718 upper_case, -1, buf, ARRAY_SIZE(buf), NULL, (void*)1, 0);
2719 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2720 ret, GetLastError(), lstrlenW(upper_case) + 1);
2721 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2723 /* crashes on native */
2724 if(0)
2725 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2726 upper_case, -1, buf, ARRAY_SIZE(buf), (void*)1, NULL, 0);
2728 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2731 struct neutralsublang_name_t {
2732 WCHAR name[3];
2733 WCHAR sname[16];
2734 LCID lcid;
2735 int todo;
2738 static const struct neutralsublang_name_t neutralsublang_names[] = {
2739 { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2740 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2741 { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2742 { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2743 { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2744 { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2745 { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2746 { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2747 { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2748 { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2749 { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2750 { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2751 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2752 { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2753 { {0} }
2756 static void test_LocaleNameToLCID(void)
2758 LCID lcid;
2759 INT ret;
2760 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2761 static const WCHAR enW[] = {'e','n',0};
2762 static const WCHAR esesW[] = {'e','s','-','e','s',0};
2763 static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
2764 static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
2765 static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
2766 static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
2767 static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
2768 static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
2770 if (!pLocaleNameToLCID)
2772 win_skip( "LocaleNameToLCID not available\n" );
2773 return;
2776 /* special cases */
2777 buffer[0] = 0;
2778 SetLastError(0xdeadbeef);
2779 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2780 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2781 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2782 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2783 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2784 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2786 buffer[0] = 0;
2787 SetLastError(0xdeadbeef);
2788 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2789 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2790 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2791 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2792 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2793 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2795 buffer[0] = 0;
2796 SetLastError(0xdeadbeef);
2797 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2798 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2799 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2800 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2801 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2803 /* bad name */
2804 SetLastError(0xdeadbeef);
2805 lcid = pLocaleNameToLCID(invalidW, 0);
2806 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2807 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2809 /* lower-case */
2810 lcid = pLocaleNameToLCID(esesW, 0);
2811 ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid);
2813 /* english neutral name */
2814 lcid = pLocaleNameToLCID(enW, 0);
2815 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2816 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2817 if (lcid)
2819 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2821 while (*ptr->name)
2823 lcid = pLocaleNameToLCID(ptr->name, 0);
2824 todo_wine_if (ptr->todo)
2825 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2826 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2828 *buffer = 0;
2829 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
2830 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2831 ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
2832 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2834 ptr++;
2837 /* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
2838 lcid = pLocaleNameToLCID(zhHantW, 0);
2839 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2840 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid);
2841 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
2842 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2843 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2844 wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2845 /* check that 0x7c04 also works and is mapped to zh-HK */
2846 ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL),
2847 buffer, ARRAY_SIZE(buffer), 0);
2848 todo_wine ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2849 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2850 wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2852 /* zh-hant */
2853 lcid = pLocaleNameToLCID(zhhantW, 0);
2854 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2855 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW), lcid);
2856 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
2857 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret);
2858 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2859 wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer));
2861 /* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */
2862 lcid = pLocaleNameToLCID(zhHansW, 0);
2863 /* check that LocaleNameToLCID actually returns 0x0804 */
2864 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2865 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid);
2866 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
2867 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2868 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2869 wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2870 /* check that 0x0004 also works and is mapped to zh-CN */
2871 ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), buffer, ARRAY_SIZE(buffer), 0);
2872 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2873 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2874 wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2876 /* zh-hans */
2877 lcid = pLocaleNameToLCID(zhhansW, 0);
2878 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2879 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW), lcid);
2880 ret = pLCIDToLocaleName(lcid, buffer, ARRAY_SIZE(buffer), 0);
2881 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret);
2882 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2883 wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
2887 /* this requires collation table patch to make it MS compatible */
2888 static const char * const strings_sorted[] =
2890 "'",
2891 "-",
2892 "!",
2893 "\"",
2894 ".",
2895 ":",
2896 "\\",
2897 "_",
2898 "`",
2899 "{",
2900 "}",
2901 "+",
2902 "0",
2903 "1",
2904 "2",
2905 "3",
2906 "4",
2907 "5",
2908 "6",
2909 "7",
2910 "8",
2911 "9",
2912 "a",
2913 "A",
2914 "b",
2915 "B",
2916 "c",
2920 static const char * const strings[] =
2922 "C",
2923 "\"",
2924 "9",
2925 "'",
2926 "}",
2927 "-",
2928 "7",
2929 "+",
2930 "`",
2931 "1",
2932 "a",
2933 "5",
2934 "\\",
2935 "8",
2936 "B",
2937 "3",
2938 "_",
2939 "6",
2940 "{",
2941 "2",
2942 "c",
2943 "4",
2944 "!",
2945 "0",
2946 "A",
2947 ":",
2948 "b",
2952 static int compare_string1(const void *e1, const void *e2)
2954 const char *s1 = *(const char *const *)e1;
2955 const char *s2 = *(const char *const *)e2;
2957 return lstrcmpA(s1, s2);
2960 static int compare_string2(const void *e1, const void *e2)
2962 const char *s1 = *(const char *const *)e1;
2963 const char *s2 = *(const char *const *)e2;
2965 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2968 static int compare_string3(const void *e1, const void *e2)
2970 const char *s1 = *(const char *const *)e1;
2971 const char *s2 = *(const char *const *)e2;
2972 char key1[256], key2[256];
2974 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2975 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2976 return strcmp(key1, key2);
2979 static void test_sorting(void)
2981 char buf[256];
2982 char **str_buf = (char **)buf;
2983 int i;
2985 assert(sizeof(buf) >= sizeof(strings));
2987 /* 1. sort using lstrcmpA */
2988 memcpy(buf, strings, sizeof(strings));
2989 qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string1);
2990 for (i = 0; i < ARRAY_SIZE(strings); i++)
2992 ok(!strcmp(strings_sorted[i], str_buf[i]),
2993 "qsort using lstrcmpA failed for element %d\n", i);
2995 /* 2. sort using CompareStringA */
2996 memcpy(buf, strings, sizeof(strings));
2997 qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string2);
2998 for (i = 0; i < ARRAY_SIZE(strings); i++)
3000 ok(!strcmp(strings_sorted[i], str_buf[i]),
3001 "qsort using CompareStringA failed for element %d\n", i);
3003 /* 3. sort using sort keys */
3004 memcpy(buf, strings, sizeof(strings));
3005 qsort(buf, ARRAY_SIZE(strings), sizeof(strings[0]), compare_string3);
3006 for (i = 0; i < ARRAY_SIZE(strings); i++)
3008 ok(!strcmp(strings_sorted[i], str_buf[i]),
3009 "qsort using sort keys failed for element %d\n", i);
3013 static void test_FoldStringA(void)
3015 int ret, i, j;
3016 BOOL is_special;
3017 char src[256], dst[256];
3018 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
3019 static const char digits_dst[] = { '1','2','3','\0' };
3020 static const char composite_src[] =
3022 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
3023 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
3024 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
3025 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
3026 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
3027 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
3028 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
3029 0xfb,0xfc,0xfd,0xff,'\0'
3031 static const char composite_dst[] =
3033 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3034 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3035 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3036 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3037 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3038 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3039 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
3040 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
3041 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
3042 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
3043 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
3044 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
3045 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
3046 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
3047 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3049 static const char composite_dst_alt[] =
3051 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
3052 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
3053 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3054 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3055 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3056 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3057 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
3058 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
3059 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
3060 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
3061 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
3062 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
3063 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
3064 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3065 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3067 static const char ligatures_src[] =
3069 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3071 static const char ligatures_dst[] =
3073 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3075 static const struct special
3077 char src;
3078 char dst[4];
3079 } foldczone_special[] =
3081 /* src dst */
3082 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3083 { 0x98, { 0x20, 0x7e, 0x00 } },
3084 { 0x99, { 0x54, 0x4d, 0x00 } },
3085 { 0xa0, { 0x20, 0x00 } },
3086 { 0xa8, { 0x20, 0xa8, 0x00 } },
3087 { 0xaa, { 0x61, 0x00 } },
3088 { 0xaf, { 0x20, 0xaf, 0x00 } },
3089 { 0xb2, { 0x32, 0x00 } },
3090 { 0xb3, { 0x33, 0x00 } },
3091 { 0xb4, { 0x20, 0xb4, 0x00 } },
3092 { 0xb8, { 0x20, 0xb8, 0x00 } },
3093 { 0xb9, { 0x31, 0x00 } },
3094 { 0xba, { 0x6f, 0x00 } },
3095 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3096 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
3097 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
3098 { 0x00 }
3101 if (!pFoldStringA)
3102 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3104 /* these tests are locale specific */
3105 if (GetACP() != 1252)
3107 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
3108 return;
3111 /* MAP_FOLDDIGITS */
3112 SetLastError(0);
3113 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
3114 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3116 win_skip("FoldStringA is not implemented\n");
3117 return;
3119 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
3120 ok(strcmp(dst, digits_dst) == 0,
3121 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
3122 for (i = 1; i < 256; i++)
3124 if (!strchr(digits_src, i))
3126 src[0] = i;
3127 src[1] = '\0';
3128 SetLastError(0);
3129 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
3130 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3131 ok(dst[0] == src[0],
3132 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3136 /* MAP_EXPAND_LIGATURES */
3137 SetLastError(0);
3138 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3139 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3140 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3141 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3142 ok(strcmp(dst, ligatures_dst) == 0,
3143 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3144 for (i = 1; i < 256; i++)
3146 if (!strchr(ligatures_src, i))
3148 src[0] = i;
3149 src[1] = '\0';
3150 SetLastError(0);
3151 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3152 if (ret == 3)
3154 /* Vista */
3155 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3156 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3157 "Got %s for %d\n", dst, i);
3159 else
3161 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3162 ok(dst[0] == src[0],
3163 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3169 /* MAP_COMPOSITE */
3170 SetLastError(0);
3171 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3172 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3173 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3174 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3175 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3177 for (i = 1; i < 256; i++)
3179 if (!strchr(composite_src, i))
3181 src[0] = i;
3182 src[1] = '\0';
3183 SetLastError(0);
3184 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3185 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3186 ok(dst[0] == src[0],
3187 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3188 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3192 /* MAP_FOLDCZONE */
3193 for (i = 1; i < 256; i++)
3195 src[0] = i;
3196 src[1] = '\0';
3197 SetLastError(0);
3198 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3199 is_special = FALSE;
3200 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3202 if (foldczone_special[j].src == src[0])
3204 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3205 "Expected ret == 2 or %d, got %d, error %d\n",
3206 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3207 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3208 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3209 (unsigned char)src[0]);
3210 is_special = TRUE;
3213 if (! is_special)
3215 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3216 ok(src[0] == dst[0],
3217 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3218 (unsigned char)src[0], (unsigned char)dst[0]);
3222 /* MAP_PRECOMPOSED */
3223 for (i = 1; i < 256; i++)
3225 src[0] = i;
3226 src[1] = '\0';
3227 SetLastError(0);
3228 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3229 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3230 ok(src[0] == dst[0],
3231 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3232 (unsigned char)src[0], (unsigned char)dst[0]);
3236 static void test_FoldStringW(void)
3238 int ret;
3239 unsigned int i, j;
3240 WCHAR src[256], dst[256], ch, prev_ch = 1;
3241 static const DWORD badFlags[] =
3244 MAP_PRECOMPOSED|MAP_COMPOSITE,
3245 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3246 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3248 /* Ranges of digits 0-9 : Must be sorted! */
3249 static const WCHAR digitRanges[] =
3251 0x0030, /* '0'-'9' */
3252 0x0660, /* Eastern Arabic */
3253 0x06F0, /* Arabic - Hindu */
3254 0x07C0, /* Nko */
3255 0x0966, /* Devengari */
3256 0x09E6, /* Bengalii */
3257 0x0A66, /* Gurmukhi */
3258 0x0AE6, /* Gujarati */
3259 0x0B66, /* Oriya */
3260 0x0BE6, /* Tamil - No 0 */
3261 0x0C66, /* Telugu */
3262 0x0CE6, /* Kannada */
3263 0x0D66, /* Maylayalam */
3264 0x0DE6, /* Sinhala Lith */
3265 0x0E50, /* Thai */
3266 0x0ED0, /* Laos */
3267 0x0F20, /* Tibet */
3268 0x0F29, /* Tibet half - 0 is out of sequence */
3269 0x1040, /* Myanmar */
3270 0x1090, /* Myanmar Shan */
3271 0x1368, /* Ethiopic - no 0 */
3272 0x17E0, /* Khmer */
3273 0x1810, /* Mongolian */
3274 0x1946, /* Limbu */
3275 0x19D0, /* New Tai Lue */
3276 0x1A80, /* Tai Tham Hora */
3277 0x1A90, /* Tai Tham Tham */
3278 0x1B50, /* Balinese */
3279 0x1BB0, /* Sundanese */
3280 0x1C40, /* Lepcha */
3281 0x1C50, /* Ol Chiki */
3282 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3283 0x2080, /* Subscript */
3284 0x245F, /* Circled - 0 is out of sequence */
3285 0x2473, /* Bracketed */
3286 0x2487, /* Full stop */
3287 0x24F4, /* Double Circled */
3288 0x2775, /* Inverted circled - No 0 */
3289 0x277F, /* Patterned circled - No 0 */
3290 0x2789, /* Inverted Patterned circled - No 0 */
3291 0x3020, /* Hangzhou */
3292 0xA620, /* Vai */
3293 0xA8D0, /* Saurashtra */
3294 0xA900, /* Kayah Li */
3295 0xA9D0, /* Javanese */
3296 0xA9F0, /* Myanmar Tai Laing */
3297 0xAA50, /* Cham */
3298 0xABF0, /* Meetei Mayek */
3299 0xff10, /* Pliene chasse (?) */
3300 0xffff /* Terminator */
3302 /* Digits which are represented, but out of sequence */
3303 static const WCHAR outOfSequenceDigits[] =
3305 0xB9, /* Superscript 1 */
3306 0xB2, /* Superscript 2 */
3307 0xB3, /* Superscript 3 */
3308 0x0C78, /* Telugu Fraction 0 */
3309 0x0C79, /* Telugu Fraction 1 */
3310 0x0C7A, /* Telugu Fraction 2 */
3311 0x0C7B, /* Telugu Fraction 3 */
3312 0x0C7C, /* Telugu Fraction 1 */
3313 0x0C7D, /* Telugu Fraction 2 */
3314 0x0C7E, /* Telugu Fraction 3 */
3315 0x0F33, /* Tibetan half zero */
3316 0x19DA, /* New Tai Lue Tham 1 */
3317 0x24EA, /* Circled 0 */
3318 0x24FF, /* Negative Circled 0 */
3319 0x3007, /* Ideographic number zero */
3320 '\0' /* Terminator */
3322 /* Digits in digitRanges for which no representation is available */
3323 static const WCHAR noDigitAvailable[] =
3325 0x0BE6, /* No Tamil 0 */
3326 0x0F29, /* No Tibetan half zero (out of sequence) */
3327 0x1368, /* No Ethiopic 0 */
3328 0x2473, /* No Bracketed 0 */
3329 0x2487, /* No 0 Full stop */
3330 0x24F4, /* No double circled 0 */
3331 0x2775, /* No inverted circled 0 */
3332 0x277F, /* No patterned circled */
3333 0x2789, /* No inverted Patterned circled */
3334 0x3020, /* No Hangzhou 0 */
3335 '\0' /* Terminator */
3337 static const WCHAR foldczone_src[] =
3339 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
3340 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3342 static const WCHAR foldczone_dst[] =
3344 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3346 static const WCHAR foldczone_todo_src[] =
3348 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3350 static const WCHAR foldczone_todo_dst[] =
3352 0x3cb,0x1f0,' ','a',0
3354 static const WCHAR foldczone_todo_broken_dst[] =
3356 0x3cb,0x1f0,0xa0,0xaa,0
3358 static const WCHAR ligatures_src[] =
3360 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
3361 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3362 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3363 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3364 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3365 0xfb04, 0xfb05, 0xfb06, '\0'
3367 static const WCHAR ligatures_dst[] =
3369 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3370 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3371 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3372 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3373 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3374 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3377 if (!pFoldStringW)
3379 win_skip("FoldStringW is not available\n");
3380 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3383 /* Invalid flag combinations */
3384 for (i = 0; i < ARRAY_SIZE(badFlags); i++)
3386 src[0] = dst[0] = '\0';
3387 SetLastError(0);
3388 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3389 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3391 win_skip("FoldStringW is not implemented\n");
3392 return;
3394 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3395 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3398 /* src & dst cannot be the same */
3399 SetLastError(0);
3400 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3401 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3402 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3404 /* src can't be NULL */
3405 SetLastError(0);
3406 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3407 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3408 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3410 /* srclen can't be 0 */
3411 SetLastError(0);
3412 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3413 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3414 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3416 /* dstlen can't be < 0 */
3417 SetLastError(0);
3418 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3419 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3420 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3422 /* Ret includes terminating NUL which is appended if srclen = -1 */
3423 SetLastError(0);
3424 src[0] = 'A';
3425 src[1] = '\0';
3426 dst[0] = '\0';
3427 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3428 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3429 ok(dst[0] == 'A' && dst[1] == '\0',
3430 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3431 'A', '\0', ret, dst[0], dst[1], GetLastError());
3433 /* If size is given, result is not NUL terminated */
3434 SetLastError(0);
3435 src[0] = 'A';
3436 src[1] = 'A';
3437 dst[0] = 'X';
3438 dst[1] = 'X';
3439 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3440 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3441 ok(dst[0] == 'A' && dst[1] == 'X',
3442 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3443 'A','X', ret, dst[0], dst[1], GetLastError());
3445 /* MAP_FOLDDIGITS */
3446 for (j = 0; j < ARRAY_SIZE(digitRanges); j++)
3448 /* Check everything before this range */
3449 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3451 SetLastError(0);
3452 src[0] = ch;
3453 src[1] = dst[0] = '\0';
3454 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3455 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3457 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3458 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3459 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3460 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3461 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3462 "char %04x should not be a digit\n", ch );
3465 if (digitRanges[j] == 0xffff)
3466 break; /* Finished the whole code point space */
3468 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3470 WCHAR c;
3472 /* Map out of sequence characters */
3473 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3474 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3475 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3476 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3477 else c = ch;
3478 SetLastError(0);
3479 src[0] = c;
3480 src[1] = dst[0] = '\0';
3481 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3482 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3484 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3485 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3486 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3487 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3488 strchrW(noDigitAvailable, c),
3489 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3490 ch, '0' + digitRanges[j] - ch, dst[0]);
3492 prev_ch = ch;
3495 /* MAP_FOLDCZONE */
3496 SetLastError(0);
3497 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3498 ok(ret == ARRAY_SIZE(foldczone_dst), "Got %d, error %d\n", ret, GetLastError());
3499 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3500 "MAP_FOLDCZONE: Expanded incorrectly\n");
3502 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3503 todo_wine ok(ret == ARRAY_SIZE(foldczone_todo_dst), "Got %d, error %d\n", ret, GetLastError());
3504 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3505 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3506 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3508 /* MAP_EXPAND_LIGATURES */
3509 SetLastError(0);
3510 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3511 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3512 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3513 ok(ret == ARRAY_SIZE(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3514 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3515 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3518 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3523 #define LCID_OK(l) \
3524 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3525 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3526 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3527 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3528 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3530 static void test_ConvertDefaultLocale(void)
3532 LCID lcid;
3534 /* Doesn't change lcid, even if non default sublang/sort used */
3535 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3536 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3537 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3538 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3540 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3541 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3542 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3543 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3544 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3546 /* Invariant language is not treated specially */
3547 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3549 /* User/system default languages alone are not mapped */
3550 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3551 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3553 /* Default lcids */
3554 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3555 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3556 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3557 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3558 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3559 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3562 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3563 DWORD dwFlags, LONG_PTR lParam)
3565 if (winetest_debug > 1)
3566 trace("%08x, %s, %s, %08x, %08lx\n",
3567 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3569 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3570 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3572 /* If lParam is one, we are calling with flags defaulted from 0 */
3573 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3574 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3576 return TRUE;
3579 static void test_EnumSystemLanguageGroupsA(void)
3581 BOOL ret;
3583 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3585 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3586 return;
3589 /* No enumeration proc */
3590 SetLastError(0);
3591 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3592 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3594 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3595 return;
3597 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3598 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3600 /* Invalid flags */
3601 SetLastError(0);
3602 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3603 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3605 /* No flags - defaults to LGRPID_INSTALLED */
3606 SetLastError(0xdeadbeef);
3607 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3608 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3610 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3611 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3614 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3616 if (winetest_debug > 1)
3617 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3618 return TRUE;
3621 static void test_EnumSystemLocalesEx(void)
3623 BOOL ret;
3625 if (!pEnumSystemLocalesEx)
3627 win_skip( "EnumSystemLocalesEx not available\n" );
3628 return;
3630 SetLastError( 0xdeadbeef );
3631 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3632 ok( !ret, "should have failed\n" );
3633 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3634 SetLastError( 0xdeadbeef );
3635 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3636 ok( ret, "failed err %u\n", GetLastError() );
3639 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3640 LONG_PTR lParam)
3642 if (winetest_debug > 1)
3643 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3645 /* invalid locale enumerated on some platforms */
3646 if (lcid == 0)
3647 return TRUE;
3649 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3650 "Enumerated grp %d not valid\n", lgrpid);
3651 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3652 "Enumerated grp locale %04x not valid\n", lcid);
3653 return TRUE;
3656 static void test_EnumLanguageGroupLocalesA(void)
3658 BOOL ret;
3660 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3662 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3663 return;
3666 /* No enumeration proc */
3667 SetLastError(0);
3668 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3669 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3671 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3672 return;
3674 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3675 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3677 /* lgrpid too small */
3678 SetLastError(0);
3679 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3680 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3681 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3683 /* lgrpid too big */
3684 SetLastError(0);
3685 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3686 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3687 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3689 /* dwFlags is reserved */
3690 SetLastError(0);
3691 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3692 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3693 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3695 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3698 static void test_SetLocaleInfoA(void)
3700 BOOL bRet;
3701 LCID lcid = GetUserDefaultLCID();
3703 /* Null data */
3704 SetLastError(0);
3705 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3706 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3707 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3709 /* IDATE */
3710 SetLastError(0);
3711 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3712 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3713 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3715 /* ILDATE */
3716 SetLastError(0);
3717 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3718 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3719 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3722 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3724 if (winetest_debug > 1)
3725 trace("%s %08lx\n", value, lParam);
3726 return(TRUE);
3729 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3731 ok(!enumCount, "callback called again unexpected\n");
3732 enumCount++;
3733 return(FALSE);
3736 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3738 ok(0,"callback called unexpected\n");
3739 return(FALSE);
3742 static void test_EnumUILanguageA(void)
3744 BOOL ret;
3745 if (!pEnumUILanguagesA) {
3746 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3747 return;
3750 SetLastError(ERROR_SUCCESS);
3751 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3752 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3754 win_skip("EnumUILanguagesA is not implemented\n");
3755 return;
3757 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3759 enumCount = 0;
3760 SetLastError(ERROR_SUCCESS);
3761 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3762 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3764 SetLastError(ERROR_SUCCESS);
3765 ret = pEnumUILanguagesA(NULL, 0, 0);
3766 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3767 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3768 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3770 SetLastError(ERROR_SUCCESS);
3771 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3772 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3773 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3775 SetLastError(ERROR_SUCCESS);
3776 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3777 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3778 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3779 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3782 static char date_fmt_buf[1024];
3783 static WCHAR date_fmt_bufW[1024];
3785 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3787 lstrcatA(date_fmt_buf, fmt);
3788 lstrcatA(date_fmt_buf, "\n");
3789 return TRUE;
3792 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3794 lstrcatW(date_fmt_bufW, fmt);
3795 return FALSE;
3798 static void test_EnumDateFormatsA(void)
3800 char *p, buf[256];
3801 BOOL ret;
3802 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3804 date_fmt_buf[0] = 0;
3805 SetLastError(0xdeadbeef);
3806 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3807 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3809 win_skip("0 for dwFlags is not supported\n");
3811 else
3813 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3814 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3815 /* test the 1st enumerated format */
3816 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3817 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3818 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3819 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3822 date_fmt_buf[0] = 0;
3823 SetLastError(0xdeadbeef);
3824 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3825 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3827 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3829 else
3831 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3832 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3833 /* test the 1st enumerated format */
3834 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3835 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3836 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3837 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3840 date_fmt_buf[0] = 0;
3841 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3842 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3843 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3844 /* test the 1st enumerated format */
3845 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3846 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3847 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3848 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3850 date_fmt_buf[0] = 0;
3851 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3852 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3853 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3854 /* test the 1st enumerated format */
3855 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3856 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3857 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3858 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3860 date_fmt_buf[0] = 0;
3861 SetLastError(0xdeadbeef);
3862 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3863 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3865 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3866 return;
3868 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3869 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3870 /* test the 1st enumerated format */
3871 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3872 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3873 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3874 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3875 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3878 static void test_EnumTimeFormatsA(void)
3880 char *p, buf[256];
3881 BOOL ret;
3882 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3884 date_fmt_buf[0] = 0;
3885 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3886 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3887 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3888 /* test the 1st enumerated format */
3889 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3890 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3891 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3892 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3894 date_fmt_buf[0] = 0;
3895 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3896 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3897 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3898 /* test the 1st enumerated format */
3899 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3900 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3901 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3902 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3905 static void test_EnumTimeFormatsW(void)
3907 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3908 WCHAR bufW[256];
3909 BOOL ret;
3911 date_fmt_bufW[0] = 0;
3912 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3913 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3914 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, ARRAY_SIZE(bufW));
3915 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3916 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3917 wine_dbgstr_w(bufW));
3919 date_fmt_bufW[0] = 0;
3920 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3921 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3922 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, ARRAY_SIZE(bufW));
3923 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3924 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3925 wine_dbgstr_w(bufW));
3927 /* TIME_NOSECONDS is Win7+ feature */
3928 date_fmt_bufW[0] = 0;
3929 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3930 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3931 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3932 else {
3933 char buf[256];
3935 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3936 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, ARRAY_SIZE(bufW));
3937 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3938 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3939 wine_dbgstr_w(bufW));
3941 /* EnumTimeFormatsA doesn't support this flag */
3942 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3943 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3944 GetLastError());
3946 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3947 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3948 GetLastError());
3950 /* And it's not supported by GetLocaleInfoA either */
3951 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, ARRAY_SIZE(buf));
3952 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3953 GetLastError());
3956 static void test_GetCPInfo(void)
3958 BOOL ret;
3959 CPINFO cpinfo;
3961 SetLastError(0xdeadbeef);
3962 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3963 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3964 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3965 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3967 SetLastError(0xdeadbeef);
3968 ret = GetCPInfo(CP_UTF7, &cpinfo);
3969 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3971 win_skip("Codepage CP_UTF7 is not installed/available\n");
3973 else
3975 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3976 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3977 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3978 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3979 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3980 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3983 SetLastError(0xdeadbeef);
3984 ret = GetCPInfo(CP_UTF8, &cpinfo);
3985 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3987 win_skip("Codepage CP_UTF8 is not installed/available\n");
3989 else
3991 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3992 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3993 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3994 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3995 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3996 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3997 "expected 4, got %u\n", cpinfo.MaxCharSize);
4002 * The CT_TYPE1 has varied over windows version.
4003 * The current target for correct behavior is windows 7.
4004 * There was a big shift between windows 2000 (first introduced) and windows Xp
4005 * Most of the old values below are from windows 2000.
4006 * A smaller subset of changes happened between windows Xp and Window vista/7
4008 static void test_GetStringTypeW(void)
4010 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
4011 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
4012 C1_SPACE | C1_BLANK | C1_DEFINED,
4013 C1_SPACE | C1_BLANK | C1_DEFINED,
4014 C1_SPACE | C1_BLANK | C1_DEFINED,
4015 C1_CNTRL | C1_BLANK | C1_DEFINED};
4016 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
4017 C1_SPACE | C1_BLANK,
4018 C1_SPACE | C1_BLANK,
4019 C1_SPACE | C1_BLANK,
4020 C1_SPACE | C1_BLANK};
4022 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
4024 /* Lu, Ll, Lt */
4025 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
4026 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
4027 C1_LOWER | C1_ALPHA,
4028 C1_UPPER | C1_LOWER | C1_ALPHA,
4029 C1_ALPHA};
4031 /* Sk, Sk, Mn, So, Me */
4032 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
4033 /* Sc, Sm, No,*/
4034 0xffe0, 0xffe9, 0x2153};
4036 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
4037 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
4038 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
4039 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
4040 C1_ALPHA | C1_DEFINED,
4041 C1_CNTRL | C1_DEFINED,
4042 C1_PUNCT | C1_DEFINED,
4043 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
4044 C1_ALPHA | C1_LOWER | C1_DEFINED,
4045 C1_ALPHA | C1_DEFINED };
4046 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
4047 C1_ALPHA | C1_DEFINED,
4048 C1_CNTRL | C1_DEFINED,
4049 C1_PUNCT | C1_CNTRL | C1_DEFINED,
4050 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
4051 C1_ALPHA | C1_DEFINED,
4052 C1_DEFINED
4054 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
4055 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
4057 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
4058 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
4059 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
4060 static const WCHAR lower_special[] = {0x2071, 0x207f};
4061 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
4062 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
4063 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
4064 0xfff9, 0xfffa, 0xfffb};
4065 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
4067 WORD types[20];
4068 WCHAR ch[2];
4069 BOOL ret;
4070 int i;
4072 /* NULL src */
4073 SetLastError(0xdeadbeef);
4074 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
4075 ok(!ret, "got %d\n", ret);
4076 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4078 SetLastError(0xdeadbeef);
4079 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
4080 ok(!ret, "got %d\n", ret);
4081 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4083 SetLastError(0xdeadbeef);
4084 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
4085 ok(!ret, "got %d\n", ret);
4086 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4088 memset(types,0,sizeof(types));
4089 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
4090 for (i = 0; i < 5; i++)
4091 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]);
4093 memset(types,0,sizeof(types));
4094 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
4095 for (i = 0; i < 3; i++)
4096 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]));
4097 memset(types,0,sizeof(types));
4098 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
4099 for (i = 0; i < 5; i++)
4100 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
4102 memset(types,0,sizeof(types));
4103 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
4104 for (i = 0; i < 8; i++)
4105 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);
4107 memset(types,0,sizeof(types));
4108 GetStringTypeW(CT_CTYPE1, changed, 7, types);
4109 for (i = 0; i < 7; i++)
4110 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]);
4112 memset(types,0,sizeof(types));
4113 GetStringTypeW(CT_CTYPE1, punct, 7, types);
4114 for (i = 0; i < 7; i++)
4115 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));
4118 memset(types,0,sizeof(types));
4119 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
4120 for (i = 0; i < 12; i++)
4121 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);
4123 memset(types,0,sizeof(types));
4124 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
4125 for (i = 0; i < 3; i++)
4126 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);
4128 memset(types,0,sizeof(types));
4129 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
4130 for (i = 0; i < 2; i++)
4131 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);
4133 memset(types,0,sizeof(types));
4134 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4135 for (i = 0; i < 20; i++)
4136 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);
4138 memset(types,0,sizeof(types));
4139 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4140 for (i = 0; i < 3; i++)
4141 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 );
4143 /* surrogate pairs */
4144 ch[0] = 0xd800;
4145 memset(types, 0, sizeof(types));
4146 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4147 if (types[0] == C3_NOTAPPLICABLE)
4148 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4149 else {
4150 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4152 ch[0] = 0xdc00;
4153 memset(types, 0, sizeof(types));
4154 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4155 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4158 /* Zl, Zp categories */
4159 ch[0] = 0x2028;
4160 ch[1] = 0x2029;
4161 memset(types, 0, sizeof(types));
4162 GetStringTypeW(CT_CTYPE1, ch, 2, types);
4163 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4164 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4166 /* check Arabic range for kashida flag */
4167 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4169 types[0] = 0;
4170 ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4171 ok(ret, "%#x: failed %d\n", ch[0], ret);
4172 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4173 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4174 else
4175 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4179 static void test_IdnToNameprepUnicode(void)
4181 struct {
4182 DWORD in_len;
4183 const WCHAR in[64];
4184 DWORD ret;
4185 DWORD broken_ret;
4186 const WCHAR out[64];
4187 DWORD flags;
4188 DWORD err;
4189 DWORD todo;
4190 } test_data[] = {
4192 5, {'t','e','s','t',0},
4193 5, 5, {'t','e','s','t',0},
4194 0, 0xdeadbeef
4197 3, {'a',0xe111,'b'},
4198 0, 0, {0},
4199 0, ERROR_INVALID_NAME
4202 4, {'t',0,'e',0},
4203 0, 0, {0},
4204 0, ERROR_INVALID_NAME
4207 1, {'T',0},
4208 1, 1, {'T',0},
4209 0, 0xdeadbeef
4212 1, {0},
4213 0, 0, {0},
4214 0, ERROR_INVALID_NAME
4217 6, {' ','-','/','[',']',0},
4218 6, 6, {' ','-','/','[',']',0},
4219 0, 0xdeadbeef
4222 3, {'a','-','a'},
4223 3, 3, {'a','-','a'},
4224 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4227 3, {'a','a','-'},
4228 0, 0, {0},
4229 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4231 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4232 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4233 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4234 0, 0xdeadbeef, TRUE
4237 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4238 2, 0, {'t',0},
4239 0, 0xdeadbeef
4241 { /* Another example of incorrectly working FoldString (composition) */
4242 2, {0x3b0, 0},
4243 2, 2, {0x3b0, 0},
4244 0, 0xdeadbeef, TRUE
4247 2, {0x221, 0},
4248 0, 2, {0},
4249 0, ERROR_NO_UNICODE_TRANSLATION
4252 2, {0x221, 0},
4253 2, 2, {0x221, 0},
4254 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4257 5, {'a','.','.','a',0},
4258 0, 0, {0},
4259 0, ERROR_INVALID_NAME
4262 3, {'a','.',0},
4263 3, 3, {'a','.',0},
4264 0, 0xdeadbeef
4268 WCHAR buf[1024];
4269 DWORD i, ret, err;
4271 if (!pIdnToNameprepUnicode)
4273 win_skip("IdnToNameprepUnicode is not available\n");
4274 return;
4277 ret = pIdnToNameprepUnicode(0, test_data[0].in,
4278 test_data[0].in_len, NULL, 0);
4279 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4281 SetLastError(0xdeadbeef);
4282 ret = pIdnToNameprepUnicode(0, test_data[1].in,
4283 test_data[1].in_len, NULL, 0);
4284 err = GetLastError();
4285 ok(ret == test_data[1].ret, "ret = %d\n", ret);
4286 ok(err == test_data[1].err, "err = %d\n", err);
4288 SetLastError(0xdeadbeef);
4289 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1, buf, ARRAY_SIZE(buf));
4290 err = GetLastError();
4291 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4292 ok(err == 0xdeadbeef, "err = %d\n", err);
4294 SetLastError(0xdeadbeef);
4295 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2, buf, ARRAY_SIZE(buf));
4296 err = GetLastError();
4297 ok(ret == 0, "ret = %d\n", ret);
4298 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4300 SetLastError(0xdeadbeef);
4301 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0, buf, ARRAY_SIZE(buf));
4302 err = GetLastError();
4303 ok(ret == 0, "ret = %d\n", ret);
4304 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4306 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4307 test_data[0].in, -1, buf, ARRAY_SIZE(buf));
4308 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4310 SetLastError(0xdeadbeef);
4311 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4312 err = GetLastError();
4313 ok(ret == 0, "ret = %d\n", ret);
4314 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4316 SetLastError(0xdeadbeef);
4317 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4318 err = GetLastError();
4319 ok(ret == 0, "ret = %d\n", ret);
4320 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4321 "err = %d\n", err);
4323 for (i=0; i<ARRAY_SIZE(test_data); i++)
4325 SetLastError(0xdeadbeef);
4326 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in, test_data[i].in_len,
4327 buf, ARRAY_SIZE(buf));
4328 err = GetLastError();
4330 todo_wine_if (test_data[i].todo)
4331 ok(ret == test_data[i].ret ||
4332 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4334 if(ret != test_data[i].ret)
4335 continue;
4337 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4338 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4339 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4343 static void test_IdnToAscii(void)
4345 struct {
4346 DWORD in_len;
4347 const WCHAR in[64];
4348 DWORD ret;
4349 const WCHAR out[64];
4350 DWORD flags;
4351 DWORD err;
4352 } test_data[] = {
4354 5, {'T','e','s','t',0},
4355 5, {'T','e','s','t',0},
4356 0, 0xdeadbeef
4359 5, {'T','e',0x017c,'s','t',0},
4360 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4361 0, 0xdeadbeef
4364 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4365 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4366 0, 0xdeadbeef
4369 3, {0x0105,'.',0},
4370 9, {'x','n','-','-','2','d','a','.',0},
4371 0, 0xdeadbeef
4374 10, {'h','t','t','p',':','/','/','t',0x0106,0},
4375 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4376 0, 0xdeadbeef
4379 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4380 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4381 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4382 0, 0xdeadbeef
4385 2, {0x221,0},
4386 8, {'x','n','-','-','6','l','a',0},
4387 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4391 WCHAR buf[1024];
4392 DWORD i, ret, err;
4394 if (!pIdnToAscii)
4396 win_skip("IdnToAscii is not available\n");
4397 return;
4400 for (i=0; i<ARRAY_SIZE(test_data); i++)
4402 SetLastError(0xdeadbeef);
4403 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4404 test_data[i].in_len, buf, sizeof(buf));
4405 err = GetLastError();
4406 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4407 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4408 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4409 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4413 static void test_IdnToUnicode(void)
4415 struct {
4416 DWORD in_len;
4417 const WCHAR in[64];
4418 DWORD ret;
4419 const WCHAR out[64];
4420 DWORD flags;
4421 DWORD err;
4422 } test_data[] = {
4424 5, {'T','e','s','.',0},
4425 5, {'T','e','s','.',0},
4426 0, 0xdeadbeef
4429 2, {0x105,0},
4430 0, {0},
4431 0, ERROR_INVALID_NAME
4434 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4435 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4436 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4437 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4438 0x05d1,0x05e8,0x05d9,0x05ea,0},
4439 0, 0xdeadbeef
4442 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4443 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4444 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4445 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4446 0, 0xdeadbeef
4449 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4450 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4451 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4452 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4453 0, {0},
4454 0, ERROR_INVALID_NAME
4457 8, {'x','n','-','-','6','l','a',0},
4458 2, {0x221,0},
4459 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4463 WCHAR buf[1024];
4464 DWORD i, ret, err;
4466 if (!pIdnToUnicode)
4468 win_skip("IdnToUnicode is not available\n");
4469 return;
4472 for (i=0; i<ARRAY_SIZE(test_data); i++)
4474 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4475 test_data[i].in_len, NULL, 0);
4476 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4478 SetLastError(0xdeadbeef);
4479 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4480 test_data[i].in_len, buf, sizeof(buf));
4481 err = GetLastError();
4482 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4483 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4484 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4485 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4489 static void test_GetLocaleInfoEx(void)
4491 static const WCHAR enW[] = {'e','n',0};
4492 WCHAR bufferW[80], buffer2[80];
4493 INT ret;
4495 if (!pGetLocaleInfoEx)
4497 win_skip("GetLocaleInfoEx not supported\n");
4498 return;
4501 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
4502 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4503 if (ret)
4505 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4506 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4507 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4508 static const WCHAR usaW[] = {'U','S','A',0};
4509 static const WCHAR enuW[] = {'E','N','U',0};
4510 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4511 DWORD val;
4513 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4514 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4516 SetLastError(0xdeadbeef);
4517 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4518 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4520 SetLastError(0xdeadbeef);
4521 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4522 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4524 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
4525 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4526 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4528 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, ARRAY_SIZE(bufferW));
4529 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4530 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4532 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, ARRAY_SIZE(bufferW));
4533 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4534 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4536 ret = pGetLocaleInfoEx(enusW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW));
4537 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4538 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4540 ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT, bufferW, ARRAY_SIZE(bufferW));
4541 ok(ret == 1, "got %d\n", ret);
4542 ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW));
4544 ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT | LOCALE_NOUSEROVERRIDE, bufferW, ARRAY_SIZE(bufferW));
4545 ok(ret == 1, "got %d\n", ret);
4546 ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW));
4548 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, ARRAY_SIZE(bufferW));
4549 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4550 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4551 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4553 skip("Non-English locale\n");
4555 else
4556 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4558 bufferW[0] = 0;
4559 SetLastError(0xdeadbeef);
4560 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
4561 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4563 while (*ptr->name)
4565 val = 0;
4566 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4567 todo_wine_if (ptr->todo)
4568 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4569 bufferW[0] = 0;
4570 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
4571 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4572 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4573 ptr++;
4576 ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, ARRAY_SIZE(bufferW));
4577 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4578 ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, ARRAY_SIZE(buffer2));
4579 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4580 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4584 static void test_IsValidLocaleName(void)
4586 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4587 static const WCHAR zzW[] = {'z','z',0};
4588 static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0};
4589 static const WCHAR zzzzW[] = {'z','z','z','z',0};
4590 BOOL ret;
4592 if (!pIsValidLocaleName)
4594 win_skip("IsValidLocaleName not supported\n");
4595 return;
4598 ret = pIsValidLocaleName(enusW);
4599 ok(ret, "IsValidLocaleName failed\n");
4600 ret = pIsValidLocaleName(zzW);
4601 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4602 ret = pIsValidLocaleName(zz_zzW);
4603 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4604 ret = pIsValidLocaleName(zzzzW);
4605 ok(!ret, "IsValidLocaleName should have failed\n");
4606 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4607 ok(ret, "IsValidLocaleName failed\n");
4608 ret = pIsValidLocaleName(NULL);
4609 ok(!ret, "IsValidLocaleName should have failed\n");
4612 static void test_CompareStringOrdinal(void)
4614 INT ret;
4615 WCHAR test1[] = { 't','e','s','t',0 };
4616 WCHAR test2[] = { 'T','e','S','t',0 };
4617 WCHAR test3[] = { 't','e','s','t','3',0 };
4618 WCHAR null1[] = { 'a',0,'a',0 };
4619 WCHAR null2[] = { 'a',0,'b',0 };
4620 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4621 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4622 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4623 WCHAR coop2[] = { 'c','o','o','p',0 };
4624 WCHAR nonascii1[] = { 0x0102,0 };
4625 WCHAR nonascii2[] = { 0x0201,0 };
4626 WCHAR ch1, ch2;
4628 if (!pCompareStringOrdinal)
4630 win_skip("CompareStringOrdinal not supported\n");
4631 return;
4634 /* Check errors */
4635 SetLastError(0xdeadbeef);
4636 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4637 ok(!ret, "Got %u, expected 0\n", ret);
4638 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4639 SetLastError(0xdeadbeef);
4640 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4641 ok(!ret, "Got %u, expected 0\n", ret);
4642 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4643 SetLastError(0xdeadbeef);
4644 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4645 ok(!ret, "Got %u, expected 0\n", ret);
4646 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4648 /* Check case */
4649 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4650 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4651 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4652 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4653 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4654 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4655 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4656 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4658 /* Check different sizes */
4659 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4660 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4661 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4662 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4664 /* Check null character */
4665 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4666 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4667 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4668 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4669 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4670 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4671 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4672 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4674 /* Check ordinal behaviour */
4675 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4676 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4677 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4678 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4679 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4680 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4681 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4682 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4684 for (ch1 = 0; ch1 < 512; ch1++)
4686 for (ch2 = 0; ch2 < 1024; ch2++)
4688 int diff = ch1 - ch2;
4689 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4690 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4691 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4692 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4693 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4694 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4695 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4700 static void test_GetGeoInfo(void)
4702 char buffA[20];
4703 INT ret;
4705 if (!pGetGeoInfoA)
4707 win_skip("GetGeoInfo is not available.\n");
4708 return;
4711 /* unassigned id */
4712 SetLastError(0xdeadbeef);
4713 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4714 ok(ret == 0, "got %d\n", ret);
4715 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
4716 broken(GetLastError() == 0xdeadbeef /* Win10 */), "got %d\n", GetLastError());
4718 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4719 ok(ret == 3, "got %d\n", ret);
4721 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4722 ok(ret == 4, "got %d\n", ret);
4724 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4725 ok(ret == 3, "got %d\n", ret);
4726 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4728 /* buffer pointer not NULL, length is 0 - return required length */
4729 buffA[0] = 'a';
4730 SetLastError(0xdeadbeef);
4731 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4732 ok(ret == 3, "got %d\n", ret);
4733 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4735 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4736 ok(ret == 4, "got %d\n", ret);
4737 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4739 /* shorter buffer */
4740 SetLastError(0xdeadbeef);
4741 buffA[1] = buffA[2] = 0;
4742 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4743 ok(ret == 0, "got %d\n", ret);
4744 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4745 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4747 /* GEO_NATION returns GEOID in a string form */
4748 buffA[0] = 0;
4749 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4750 ok(ret == 4, "got %d\n", ret);
4751 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4753 /* GEO_PARENT */
4754 buffA[0] = 0;
4755 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4756 if (ret == 0)
4757 win_skip("GEO_PARENT not supported.\n");
4758 else
4760 ok(ret == 6, "got %d\n", ret);
4761 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4764 buffA[0] = 0;
4765 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4766 if (ret == 0)
4767 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4768 else
4770 ok(ret == 4, "got %d\n", ret);
4771 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4774 /* try invalid type value */
4775 SetLastError(0xdeadbeef);
4776 ret = pGetGeoInfoA(203, GEO_ID + 1, NULL, 0, 0);
4777 ok(ret == 0, "got %d\n", ret);
4778 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4781 static int geoidenum_count;
4782 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4784 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4785 ok(ret == 3, "got %d for %d\n", ret, geoid);
4786 /* valid geoid starts at 2 */
4787 ok(geoid >= 2, "got geoid %d\n", geoid);
4789 return geoidenum_count++ < 5;
4792 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4794 geoidenum_count++;
4795 return TRUE;
4798 static void test_EnumSystemGeoID(void)
4800 BOOL ret;
4802 if (!pEnumSystemGeoID)
4804 win_skip("EnumSystemGeoID is not available.\n");
4805 return;
4808 SetLastError(0xdeadbeef);
4809 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4810 ok(!ret, "got %d\n", ret);
4811 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4813 SetLastError(0xdeadbeef);
4814 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4815 ok(!ret, "got %d\n", ret);
4816 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4818 SetLastError(0xdeadbeef);
4819 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4820 ok(!ret, "got %d\n", ret);
4821 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4823 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4824 ok(ret, "got %d\n", ret);
4826 /* only the first level is enumerated, not the whole hierarchy */
4827 geoidenum_count = 0;
4828 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4829 if (ret == 0)
4830 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4831 else
4832 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4834 geoidenum_count = 0;
4835 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4836 if (ret == 0)
4837 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4838 else
4840 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4842 geoidenum_count = 0;
4843 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4844 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4848 struct invariant_entry {
4849 const char *name;
4850 int id;
4851 const char *expect, *expect2;
4854 #define X(x) #x, x
4855 static const struct invariant_entry invariant_list[] = {
4856 { X(LOCALE_ILANGUAGE), "007f" },
4857 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4858 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4859 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4860 { X(LOCALE_ICOUNTRY), "1" },
4861 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4862 { X(LOCALE_SABBREVCTRYNAME), "IVC", "" },
4863 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4864 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4865 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4866 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4867 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4868 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4869 { X(LOCALE_SLIST), "," },
4870 { X(LOCALE_IMEASURE), "0" },
4871 { X(LOCALE_SDECIMAL), "." },
4872 { X(LOCALE_STHOUSAND), "," },
4873 { X(LOCALE_SGROUPING), "3;0" },
4874 { X(LOCALE_IDIGITS), "2" },
4875 { X(LOCALE_ILZERO), "1" },
4876 { X(LOCALE_INEGNUMBER), "1" },
4877 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4878 { X(LOCALE_SCURRENCY), "\x00a4" },
4879 { X(LOCALE_SINTLSYMBOL), "XDR" },
4880 { X(LOCALE_SMONDECIMALSEP), "." },
4881 { X(LOCALE_SMONTHOUSANDSEP), "," },
4882 { X(LOCALE_SMONGROUPING), "3;0" },
4883 { X(LOCALE_ICURRDIGITS), "2" },
4884 { X(LOCALE_IINTLCURRDIGITS), "2" },
4885 { X(LOCALE_ICURRENCY), "0" },
4886 { X(LOCALE_INEGCURR), "0" },
4887 { X(LOCALE_SDATE), "/" },
4888 { X(LOCALE_STIME), ":" },
4889 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4890 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4891 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4892 { X(LOCALE_IDATE), "0" },
4893 { X(LOCALE_ILDATE), "1" },
4894 { X(LOCALE_ITIME), "1" },
4895 { X(LOCALE_ITIMEMARKPOSN), "0" },
4896 { X(LOCALE_ICENTURY), "1" },
4897 { X(LOCALE_ITLZERO), "1" },
4898 { X(LOCALE_IDAYLZERO), "1" },
4899 { X(LOCALE_IMONLZERO), "1" },
4900 { X(LOCALE_S1159), "AM" },
4901 { X(LOCALE_S2359), "PM" },
4902 { X(LOCALE_ICALENDARTYPE), "1" },
4903 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4904 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4905 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4906 { X(LOCALE_SDAYNAME1), "Monday" },
4907 { X(LOCALE_SDAYNAME2), "Tuesday" },
4908 { X(LOCALE_SDAYNAME3), "Wednesday" },
4909 { X(LOCALE_SDAYNAME4), "Thursday" },
4910 { X(LOCALE_SDAYNAME5), "Friday" },
4911 { X(LOCALE_SDAYNAME6), "Saturday" },
4912 { X(LOCALE_SDAYNAME7), "Sunday" },
4913 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4914 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4915 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4916 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4917 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4918 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4919 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4920 { X(LOCALE_SMONTHNAME1), "January" },
4921 { X(LOCALE_SMONTHNAME2), "February" },
4922 { X(LOCALE_SMONTHNAME3), "March" },
4923 { X(LOCALE_SMONTHNAME4), "April" },
4924 { X(LOCALE_SMONTHNAME5), "May" },
4925 { X(LOCALE_SMONTHNAME6), "June" },
4926 { X(LOCALE_SMONTHNAME7), "July" },
4927 { X(LOCALE_SMONTHNAME8), "August" },
4928 { X(LOCALE_SMONTHNAME9), "September" },
4929 { X(LOCALE_SMONTHNAME10), "October" },
4930 { X(LOCALE_SMONTHNAME11), "November" },
4931 { X(LOCALE_SMONTHNAME12), "December" },
4932 { X(LOCALE_SMONTHNAME13), "" },
4933 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4934 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4935 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4936 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4937 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4938 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4939 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4940 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4941 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4942 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4943 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4944 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4945 { X(LOCALE_SABBREVMONTHNAME13), "" },
4946 { X(LOCALE_SPOSITIVESIGN), "+" },
4947 { X(LOCALE_SNEGATIVESIGN), "-" },
4948 { X(LOCALE_IPOSSIGNPOSN), "3" },
4949 { X(LOCALE_INEGSIGNPOSN), "0" },
4950 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4951 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4952 { X(LOCALE_INEGSYMPRECEDES), "1" },
4953 { X(LOCALE_INEGSEPBYSPACE), "0" },
4954 { X(LOCALE_SISO639LANGNAME), "iv" },
4955 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4956 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4957 { X(LOCALE_IPAPERSIZE), "9" },
4958 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4959 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4960 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4961 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4962 { X(LOCALE_SNAME), "" },
4963 { X(LOCALE_SSCRIPTS), "Latn;" },
4964 { 0 }
4966 #undef X
4968 static void test_invariant(void)
4970 int ret;
4971 int len;
4972 char buffer[BUFFER_SIZE];
4973 const struct invariant_entry *ptr = invariant_list;
4975 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4977 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4978 return;
4981 while (ptr->name)
4983 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4984 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4985 win_skip("not supported\n"); /* winxp/win2k3 */
4986 else
4988 len = strlen(ptr->expect)+1; /* include \0 */
4989 ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
4990 "For id %d, expected ret == %d, got %d, error %d\n",
4991 ptr->id, len, ret, GetLastError());
4992 ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
4993 "For id %d, Expected %s, got '%s'\n",
4994 ptr->id, ptr->expect, buffer);
4997 ptr++;
5000 if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) ||
5001 (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
5003 skip("Non US-English locale\n");
5005 else
5007 /* some locales translate these */
5008 static const char lang[] = "Invariant Language (Invariant Country)";
5009 static const char cntry[] = "Invariant Country";
5010 static const char sortm[] = "Math Alphanumerics";
5011 static const char sortd[] = "Default"; /* win2k3 */
5013 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
5014 len = lstrlenA(lang) + 1;
5015 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
5016 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
5018 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
5019 len = lstrlenA(cntry) + 1;
5020 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
5021 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
5023 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
5024 if (ret == lstrlenA(sortm)+1)
5025 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
5026 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
5027 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
5028 else
5029 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
5030 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
5034 static void test_GetSystemPreferredUILanguages(void)
5036 BOOL ret;
5037 ULONG count, size, size_id, size_name, size_buffer;
5038 WCHAR *buffer;
5041 if (!pGetSystemPreferredUILanguages)
5043 win_skip("GetSystemPreferredUILanguages is not available.\n");
5044 return;
5047 /* (in)valid first parameter */
5048 count = 0xdeadbeef;
5049 size = 0;
5050 SetLastError(0xdeadbeef);
5051 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
5052 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5053 ok(count, "Expected count > 0\n");
5054 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5056 count = 0xdeadbeef;
5057 size = 0;
5058 SetLastError(0xdeadbeef);
5059 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5060 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5061 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5062 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5064 count = 0xdeadbeef;
5065 size = 0;
5066 SetLastError(0xdeadbeef);
5067 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5068 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5069 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5070 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5072 count = 0xdeadbeef;
5073 size = 0;
5074 SetLastError(0xdeadbeef);
5075 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
5076 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5077 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5078 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5080 count = 0xdeadbeef;
5081 size = 0;
5082 SetLastError(0xdeadbeef);
5083 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5084 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5085 ok(count, "Expected count > 0\n");
5086 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5088 count = 0xdeadbeef;
5089 size = 0;
5090 SetLastError(0xdeadbeef);
5091 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5092 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5093 ok(count, "Expected count > 0\n");
5094 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5096 /* second parameter
5097 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
5098 * -> unhandled exception c0000005
5101 /* invalid third parameter */
5102 count = 0xdeadbeef;
5103 size = 1;
5104 SetLastError(0xdeadbeef);
5105 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5106 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5107 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5108 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5110 /* fourth parameter
5111 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
5112 * -> unhandled exception c0000005
5115 count = 0xdeadbeef;
5116 size_id = 0;
5117 SetLastError(0xdeadbeef);
5118 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5119 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5120 ok(count, "Expected count > 0\n");
5121 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5123 count = 0xdeadbeef;
5124 size_name = 0;
5125 SetLastError(0xdeadbeef);
5126 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5127 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5128 ok(count, "Expected count > 0\n");
5129 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5131 size_buffer = max(size_id, size_name);
5132 if(!size_buffer)
5134 skip("No valid buffer size\n");
5135 return;
5138 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5139 if (!buffer)
5141 skip("Failed to allocate memory for %d chars\n", size_buffer);
5142 return;
5145 count = 0xdeadbeef;
5146 size = size_buffer;
5147 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5148 SetLastError(0xdeadbeef);
5149 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5150 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5151 ok(count, "Expected count > 0\n");
5152 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5153 if (ret && size % 6 == 1)
5154 ok(!buffer[size -2] && !buffer[size -1],
5155 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5156 buffer[size -2], buffer[size -1]);
5158 count = 0xdeadbeef;
5159 size = size_buffer;
5160 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5161 SetLastError(0xdeadbeef);
5162 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5163 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5164 ok(count, "Expected count > 0\n");
5165 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5166 if (ret && size % 5 == 1)
5167 ok(!buffer[size -2] && !buffer[size -1],
5168 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5169 buffer[size -2], buffer[size -1]);
5171 count = 0xdeadbeef;
5172 size = size_buffer;
5173 SetLastError(0xdeadbeef);
5174 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5175 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5176 ok(count, "Expected count > 0\n");
5177 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5178 if (ret && size % 5 == 1)
5179 ok(!buffer[size -2] && !buffer[size -1],
5180 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5181 buffer[size -2], buffer[size -1]);
5183 count = 0xdeadbeef;
5184 size = 0;
5185 SetLastError(0xdeadbeef);
5186 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5187 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5188 ok(count, "Expected count > 0\n");
5189 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5190 if (ret && size % 6 == 1)
5191 ok(!buffer[size -2] && !buffer[size -1],
5192 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5193 buffer[size -2], buffer[size -1]);
5195 count = 0xdeadbeef;
5196 size = 1;
5197 SetLastError(0xdeadbeef);
5198 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5199 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5200 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5201 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5203 count = 0xdeadbeef;
5204 size = size_id -1;
5205 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5206 SetLastError(0xdeadbeef);
5207 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5208 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5209 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5210 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5212 count = 0xdeadbeef;
5213 size = size_id -2;
5214 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5215 SetLastError(0xdeadbeef);
5216 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5217 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5218 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5219 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5221 HeapFree(GetProcessHeap(), 0, buffer);
5224 static void test_GetThreadPreferredUILanguages(void)
5226 BOOL ret;
5227 ULONG count, size;
5228 WCHAR *buf;
5230 if (!pGetThreadPreferredUILanguages)
5232 win_skip("GetThreadPreferredUILanguages is not available.\n");
5233 return;
5236 size = count = 0;
5237 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5238 ok(ret, "got %u\n", GetLastError());
5239 ok(count, "expected count > 0\n");
5240 ok(size, "expected size > 0\n");
5242 count = 0;
5243 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5244 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5245 ok(ret, "got %u\n", GetLastError());
5246 ok(count, "expected count > 0\n");
5247 HeapFree(GetProcessHeap(), 0, buf);
5250 static void test_GetUserPreferredUILanguages(void)
5252 BOOL ret;
5253 ULONG count, size, size_id, size_name, size_buffer;
5254 WCHAR *buffer;
5257 if (!pGetUserPreferredUILanguages)
5259 win_skip("GetUserPreferredUILanguages is not available.\n");
5260 return;
5263 count = 0xdeadbeef;
5264 size = 0;
5265 SetLastError(0xdeadbeef);
5266 ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5267 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5268 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5269 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5271 count = 0xdeadbeef;
5272 size = 0;
5273 SetLastError(0xdeadbeef);
5274 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5275 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5276 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5277 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5279 count = 0xdeadbeef;
5280 size = 0;
5281 SetLastError(0xdeadbeef);
5282 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5283 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5284 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5285 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5287 count = 0xdeadbeef;
5288 size = 1;
5289 SetLastError(0xdeadbeef);
5290 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5291 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5292 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5293 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5295 count = 0xdeadbeef;
5296 size_id = 0;
5297 SetLastError(0xdeadbeef);
5298 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5299 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5300 ok(count, "Expected count > 0\n");
5301 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5303 count = 0xdeadbeef;
5304 size_name = 0;
5305 SetLastError(0xdeadbeef);
5306 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5307 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5308 ok(count, "Expected count > 0\n");
5309 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5311 size_buffer = max(size_id, size_name);
5312 if(!size_buffer)
5314 skip("No valid buffer size\n");
5315 return;
5318 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5320 count = 0xdeadbeef;
5321 size = size_buffer;
5322 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5323 SetLastError(0xdeadbeef);
5324 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5325 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5326 ok(count, "Expected count > 0\n");
5327 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5328 if (ret && size % 6 == 1)
5329 ok(!buffer[size -2] && !buffer[size -1],
5330 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5331 buffer[size -2], buffer[size -1]);
5333 count = 0xdeadbeef;
5334 size = size_buffer;
5335 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5336 SetLastError(0xdeadbeef);
5337 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5338 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5339 ok(count, "Expected count > 0\n");
5340 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5341 if (ret && size % 5 == 1)
5342 ok(!buffer[size -2] && !buffer[size -1],
5343 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5344 buffer[size -2], buffer[size -1]);
5346 count = 0xdeadbeef;
5347 size = size_buffer;
5348 SetLastError(0xdeadbeef);
5349 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5350 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5351 ok(count, "Expected count > 0\n");
5352 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5353 if (ret && size % 5 == 1)
5354 ok(!buffer[size -2] && !buffer[size -1],
5355 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5356 buffer[size -2], buffer[size -1]);
5358 count = 0xdeadbeef;
5359 size = 1;
5360 SetLastError(0xdeadbeef);
5361 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5362 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5363 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5364 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5366 count = 0xdeadbeef;
5367 size = size_id -1;
5368 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5369 SetLastError(0xdeadbeef);
5370 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5371 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5372 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5373 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5375 count = 0xdeadbeef;
5376 size = size_id -2;
5377 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5378 SetLastError(0xdeadbeef);
5379 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5380 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5381 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5382 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5384 HeapFree(GetProcessHeap(), 0, buffer);
5387 static void test_FindNLSStringEx(void)
5389 INT res;
5390 static WCHAR en_simpsimpW[] = {'S','i','m','p','l','e','S','i','m','p','l','e',0};
5391 static WCHAR en_simpW[] = {'S','i','m','p','l','e',0};
5392 static WCHAR comb_s_accent1W[] = {0x1e69, 'o','u','r','c','e',0};
5393 static WCHAR comb_s_accent2W[] = {0x0073,0x323,0x307,'o','u','r','c','e',0};
5394 static WCHAR comb_q_accent1W[] = {0x0071,0x0307,0x323,'u','o','t','e',0};
5395 static WCHAR comb_q_accent2W[] = {0x0071,0x0323,0x307,'u','o','t','e',0};
5396 struct test_data {
5397 const WCHAR *locale;
5398 DWORD flags;
5399 WCHAR *src;
5400 INT src_size;
5401 WCHAR *value;
5402 INT val_size;
5403 INT found;
5404 INT expected_ret;
5405 INT expected_found;
5406 int todo;
5407 BOOL broken_vista_servers;
5410 static struct test_data test_arr[] =
5412 { localeW, FIND_FROMSTART, en_simpsimpW, ARRAY_SIZE(en_simpsimpW)-1,
5413 en_simpW, ARRAY_SIZE(en_simpW)-1, 0, 0, 6, 0, FALSE},
5414 { localeW, FIND_FROMEND, en_simpsimpW, ARRAY_SIZE(en_simpsimpW)-1,
5415 en_simpW, ARRAY_SIZE(en_simpW)-1, 0, 6, 6, 0, FALSE},
5416 { localeW, FIND_STARTSWITH, en_simpsimpW, ARRAY_SIZE(en_simpsimpW)-1,
5417 en_simpW, ARRAY_SIZE(en_simpW)-1, 0, 0, 6, 0, FALSE},
5418 { localeW, FIND_ENDSWITH, en_simpsimpW, ARRAY_SIZE(en_simpsimpW)-1,
5419 en_simpW, ARRAY_SIZE(en_simpW)-1, 0, 6, 6, 0, FALSE},
5420 { localeW, FIND_FROMSTART, comb_s_accent1W, ARRAY_SIZE(comb_s_accent1W)-1,
5421 comb_s_accent2W, ARRAY_SIZE(comb_s_accent2W)-1, 0, 0, 6, 1, TRUE },
5422 { localeW, FIND_FROMSTART, comb_q_accent1W, ARRAY_SIZE(comb_q_accent1W)-1,
5423 comb_q_accent2W, ARRAY_SIZE(comb_q_accent2W)-1, 0, 0, 7, 1, FALSE },
5424 { 0 }
5426 struct test_data *ptest;
5428 if (!pFindNLSStringEx)
5430 win_skip("FindNLSStringEx is not available.\n");
5431 return;
5434 SetLastError( 0xdeadbeef );
5435 res = pFindNLSStringEx(invalidW, FIND_FROMSTART, fooW, 3, fooW,
5436 3, NULL, NULL, NULL, 0);
5437 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5438 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5439 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5441 SetLastError( 0xdeadbeef );
5442 res = pFindNLSStringEx(localeW, FIND_FROMSTART, NULL, 3, fooW, 3,
5443 NULL, NULL, NULL, 0);
5444 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5445 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5446 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5448 SetLastError( 0xdeadbeef );
5449 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, -5, fooW, 3,
5450 NULL, NULL, NULL, 0);
5451 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5452 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5453 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5455 SetLastError( 0xdeadbeef );
5456 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, NULL, 3,
5457 NULL, NULL, NULL, 0);
5458 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5459 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5460 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5462 SetLastError( 0xdeadbeef );
5463 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, fooW, -5,
5464 NULL, NULL, NULL, 0);
5465 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5466 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5467 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5469 for (ptest = test_arr; ptest->src != NULL; ptest++)
5471 todo_wine_if(ptest->todo)
5473 res = pFindNLSStringEx(ptest->locale, ptest->flags, ptest->src, ptest->src_size,
5474 ptest->value, ptest->val_size, &ptest->found, NULL, NULL, 0);
5475 if (ptest->broken_vista_servers)
5477 ok(res == ptest->expected_ret || /* Win 7 onwards */
5478 broken(res == -1), /* Win Vista, Server 2003 and 2008 */
5479 "Expected FindNLSStringEx to return %d. Returned value was %d\n",
5480 ptest->expected_ret, res);
5481 ok(ptest->found == ptest->expected_found || /* Win 7 onwards */
5482 broken(ptest->found == 0), /* Win Vista, Server 2003 and 2008 */
5483 "Expected FindNLSStringEx to output %d. Value was %d\n",
5484 ptest->expected_found, ptest->found);
5486 else
5488 ok(res == ptest->expected_ret,
5489 "Expected FindNLSStringEx to return %d. Returned value was %d\n",
5490 ptest->expected_ret, res);
5491 ok(ptest->found == ptest->expected_found,
5492 "Expected FindNLSStringEx to output %d. Value was %d\n",
5493 ptest->expected_found, ptest->found);
5499 static void test_SetThreadUILanguage(void)
5501 LANGID res;
5503 if (!pGetThreadUILanguage)
5505 win_skip("GetThreadUILanguage isn't implemented, skipping SetThreadUILanguage tests for version < Vista\n");
5506 return; /* BTW SetThreadUILanguage is present on winxp/2003 but doesn`t set the LANGID anyway when tested */
5509 res = pSetThreadUILanguage(0);
5510 ok(res == pGetThreadUILanguage(), "expected %d got %d\n", pGetThreadUILanguage(), res);
5512 res = pSetThreadUILanguage(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN));
5513 ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN),
5514 "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res);
5516 res = pSetThreadUILanguage(0);
5517 todo_wine ok(res == MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN),
5518 "expected %d got %d\n", MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), res);
5521 static void test_NormalizeString(void)
5523 /* part 0: specific cases */
5524 /* LATIN CAPITAL LETTER D WITH DOT ABOVE */
5525 static const WCHAR part0_str1[] = {0x1e0a,0};
5526 static const WCHAR part0_nfd1[] = {0x0044,0x0307,0};
5528 /* LATIN CAPITAL LETTER D, COMBINING DOT BELOW, COMBINING DOT ABOVE */
5529 static const WCHAR part0_str2[] = {0x0044,0x0323,0x0307,0};
5530 static const WCHAR part0_nfc2[] = {0x1e0c,0x0307,0};
5532 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
5533 static const WCHAR part0_str3[] = {0x0044,0x031b,0x0323,0x0307,0};
5534 static const WCHAR part0_nfc3[] = {0x1e0c,0x031b,0x0307,0};
5536 /* LATIN CAPITAL LETTER D, COMBINING HORN, COMBINING DOT BELOW, COMBINING DOT ABOVE */
5537 static const WCHAR part0_str4[] = {0x0044,0x031b,0x0323,0x0307,0};
5538 static const WCHAR part0_nfc4[] = {0x1e0c,0x031b,0x0307,0};
5541 * HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ,
5542 * HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ,
5543 * HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI
5545 static const WCHAR part0_str5[] = {0x0592,0x05B7,0x05BC,0x05A5,0x05B0,0x05C0,0x05C4,0x05AD,0};
5546 static const WCHAR part0_nfc5[] = {0x05B0,0x05B7,0x05BC,0x05A5,0x0592,0x05C0,0x05AD,0x05C4,0};
5549 * HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL,
5550 * HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA,
5551 * HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA
5553 static const WCHAR part0_str6[] = {0x05B8,0x05B9,0x05B1,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
5554 static const WCHAR part0_nfc6[] = {0x05B1,0x05B8,0x05B9,0x0591,0x05C3,0x05B0,0x05AC,0x059F,0};
5556 /* LATIN CAPITAL LETTER D WITH DOT BELOW */
5557 static const WCHAR part0_str8[] = {0x1E0C,0};
5558 static const WCHAR part0_nfd8[] = {0x0044,0x0323,0};
5560 /* LATIN CAPITAL LETTER D WITH DOT ABOVE, COMBINING DOT BELOW */
5561 static const WCHAR part0_str9[] = {0x1E0A,0x0323,0};
5562 static const WCHAR part0_nfc9[] = {0x1E0C,0x0307,0};
5563 static const WCHAR part0_nfd9[] = {0x0044,0x0323,0x0307,0};
5565 /* LATIN CAPITAL LETTER D WITH DOT BELOW, COMBINING DOT ABOVE */
5566 static const WCHAR part0_str10[] = {0x1E0C,0x0307,0};
5567 static const WCHAR part0_nfd10[] = {0x0044,0x0323,0x0307,0};
5569 /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE, COMBINING MACRON */
5570 static const WCHAR part0_str11[] = {0x1E14,0x0304,0};
5571 static const WCHAR part0_nfd11[] = {0x0045,0x0304,0x0300,0x0304,0};
5573 /* LATIN CAPITAL LETTER E WITH MACRON, COMBINING GRAVE ACCENT */
5574 static const WCHAR part0_str12[] = {0x0112,0x0300,0};
5575 static const WCHAR part0_nfc12[] = {0x1E14,0};
5576 static const WCHAR part0_nfd12[] = {0x0045,0x0304,0x0300,0};
5578 /* part 1: character by character */
5579 /* DIAERESIS */
5580 static const WCHAR part1_str1[] = {0x00a8,0};
5581 static const WCHAR part1_nfkc1[] = {0x0020,0x0308,0};
5583 /* VULGAR FRACTION ONE QUARTER */
5584 static const WCHAR part1_str2[] = {0x00bc,0};
5585 static const WCHAR part1_nfkc2[] = {0x0031,0x2044,0x0034,0};
5587 /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
5588 static const WCHAR part1_str3[] = {0x00ca,0};
5589 static const WCHAR part1_nfd3[] = {0x0045,0x0302,0};
5591 /* MODIFIER LETTER SMALL GAMMA */
5592 static const WCHAR part1_str4[] = {0x02e0,0};
5593 static const WCHAR part1_nfkc4[] = {0x0263,0};
5595 /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */
5596 static const WCHAR part1_str5[] = {0x0400,0};
5597 static const WCHAR part1_nfd5[] = {0x0415,0x0300,0};
5599 /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */
5600 static const WCHAR part1_str6[] = {0x0476,0};
5601 static const WCHAR part1_nfd6[] = {0x0474,0x030F,0};
5603 /* ARABIC LIGATURE HAH WITH JEEM INITIAL FORM */
5604 static const WCHAR part1_str7[] = {0xFCA9,0};
5605 static const WCHAR part1_nfkc7[] = {0x062D,0x062C,0};
5607 /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */
5608 static const WCHAR part1_str8[] = {0x1F42,0};
5609 static const WCHAR part1_nfd8[] = {0x03BF,0x0313,0x0300,0};
5611 /* QUADRUPLE PRIME */
5612 static const WCHAR part1_str9[] = {0x2057,0};
5613 static const WCHAR part1_nfkc9[] = {0x2032,0x2032,0x2032,0x2032,0};
5615 /* KATAKANA-HIRAGANA VOICED SOUND MARK */
5616 static const WCHAR part1_str10[] = {0x309B,0};
5617 static const WCHAR part1_nfkc10[] = {0x20,0x3099,0};
5619 struct test_data_normal {
5620 const WCHAR *str;
5621 const WCHAR *expected[4];
5623 static const struct test_data_normal test_arr[] =
5625 { part0_str1, { part0_str1, part0_nfd1, part0_str1, part0_nfd1 } },
5626 { part0_str2, { part0_nfc2, part0_str2, part0_nfc2, part0_str2 } },
5627 { part0_str3, { part0_nfc3, part0_str3, part0_nfc3, part0_str3 } },
5628 { part0_str4, { part0_nfc4, part0_str4, part0_nfc4, part0_str4 } },
5629 { part0_str5, { part0_nfc5, part0_nfc5, part0_nfc5, part0_nfc5 } },
5630 { part0_str6, { part0_nfc6, part0_nfc6, part0_nfc6, part0_nfc6 } },
5631 { part0_str8, { part0_str8, part0_nfd8, part0_str8, part0_nfd8 } },
5632 { part0_str9, { part0_nfc9, part0_nfd9, part0_nfc9, part0_nfd9 } },
5633 { part0_str10, { part0_str10, part0_nfd10, part0_str10, part0_nfd10 } },
5634 { part0_str11, { part0_str11, part0_nfd11, part0_str11, part0_nfd11 } },
5635 { part0_str12, { part0_nfc12, part0_nfd12, part0_nfc12, part0_nfd12 } },
5636 { part1_str1, { part1_str1, part1_str1, part1_nfkc1, part1_nfkc1 } },
5637 { part1_str2, { part1_str2, part1_str2, part1_nfkc2, part1_nfkc2 } },
5638 { part1_str3, { part1_str3, part1_nfd3, part1_str3, part1_nfd3 } },
5639 { part1_str4, { part1_str4, part1_str4, part1_nfkc4, part1_nfkc4 } },
5640 { part1_str5, { part1_str5, part1_nfd5, part1_str5, part1_nfd5 } },
5641 { part1_str6, { part1_str6, part1_nfd6, part1_str6, part1_nfd6 } },
5642 { part1_str7, { part1_str7, part1_str7, part1_nfkc7, part1_nfkc7 } },
5643 { part1_str8, { part1_str8, part1_nfd8, part1_str8, part1_nfd8 } },
5644 { part1_str9, { part1_str9, part1_str9, part1_nfkc9, part1_nfkc9 } },
5645 { part1_str10, { part1_str10, part1_str10, part1_nfkc10, part1_nfkc10 } },
5646 { 0 }
5648 const struct test_data_normal *ptest = test_arr;
5649 const int norm_forms[] = { NormalizationC, NormalizationD, NormalizationKC, NormalizationKD };
5650 WCHAR dst[80];
5651 int dstlen;
5653 if (!pNormalizeString)
5655 win_skip("NormalizeString is not available.\n");
5656 return;
5659 todo_wine {
5660 dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
5661 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER\n");
5665 * For each string, first test passing -1 as srclen to NormalizeString,
5666 * thereby assuming a null-terminating string in src, and then test passing
5667 * explicitly the string length.
5668 * Do that for all 4 normalization forms.
5670 while (ptest->str)
5672 int str_cmp, i;
5674 for (i = 0; i < 4; i++)
5676 todo_wine {
5677 dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
5678 if (dstlen)
5680 dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
5681 ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
5682 dstlen, strlenW( ptest->expected[i] )+1);
5683 str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
5684 ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
5687 dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
5688 if (dstlen)
5690 dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
5691 ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
5692 dstlen, strlenW( ptest->expected[i] ));
5693 str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
5694 ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
5698 ptest++;
5702 START_TEST(locale)
5704 InitFunctionPointers();
5706 test_EnumTimeFormatsA();
5707 test_EnumTimeFormatsW();
5708 test_EnumDateFormatsA();
5709 test_GetLocaleInfoA();
5710 test_GetLocaleInfoW();
5711 test_GetLocaleInfoEx();
5712 test_GetTimeFormatA();
5713 test_GetTimeFormatEx();
5714 test_GetDateFormatA();
5715 test_GetDateFormatEx();
5716 test_GetDateFormatW();
5717 test_GetCurrencyFormatA(); /* Also tests the W version */
5718 test_GetNumberFormatA(); /* Also tests the W version */
5719 test_GetNumberFormatEx();
5720 test_CompareStringA();
5721 test_CompareStringW();
5722 test_CompareStringEx();
5723 test_LCMapStringA();
5724 test_LCMapStringW();
5725 test_LCMapStringEx();
5726 test_LocaleNameToLCID();
5727 test_FoldStringA();
5728 test_FoldStringW();
5729 test_ConvertDefaultLocale();
5730 test_EnumSystemLanguageGroupsA();
5731 test_EnumSystemLocalesEx();
5732 test_EnumLanguageGroupLocalesA();
5733 test_SetLocaleInfoA();
5734 test_EnumUILanguageA();
5735 test_GetCPInfo();
5736 test_GetStringTypeW();
5737 test_IdnToNameprepUnicode();
5738 test_IdnToAscii();
5739 test_IdnToUnicode();
5740 test_IsValidLocaleName();
5741 test_CompareStringOrdinal();
5742 test_GetGeoInfo();
5743 test_EnumSystemGeoID();
5744 test_invariant();
5745 test_GetSystemPreferredUILanguages();
5746 test_GetThreadPreferredUILanguages();
5747 test_GetUserPreferredUILanguages();
5748 test_FindNLSStringEx();
5749 test_SetThreadUILanguage();
5750 test_NormalizeString();
5751 /* this requires collation table patch to make it MS compatible */
5752 if (0) test_sorting();