kernel32: Implement IsValidLocaleName (with tests).
[wine/multimedia.git] / dlls / kernel32 / tests / locale.c
bloba2a33faa994bc1b7cfa167f0e66b83df62e005da
1 /*
2 * Unit tests for locale functions
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * NOTES
23 * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24 * even when the user has overridden their default i8n settings (e.g. in
25 * the control panel i8n page), we will still get the expected results.
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
39 static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
40 static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
41 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
42 static const WCHAR fooW[] = {'f','o','o',0};
44 static inline unsigned int strlenW( const WCHAR *str )
46 const WCHAR *s = str;
47 while (*s) s++;
48 return s - str;
51 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
53 if (n <= 0) return 0;
54 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
55 return *str1 - *str2;
58 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
60 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
61 return NULL;
64 static inline int isdigitW( WCHAR wc )
66 WORD type;
67 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
68 return type & C1_DIGIT;
71 /* Some functions are only in later versions of kernel32.dll */
72 static HMODULE hKernel32;
73 static WORD enumCount;
75 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
76 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
77 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
78 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
79 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
80 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
81 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
82 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
83 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
84 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
85 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
86 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
87 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
91 static void InitFunctionPointers(void)
93 hKernel32 = GetModuleHandleA("kernel32");
94 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
95 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
96 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
97 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
98 pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
99 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
100 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
101 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
102 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
103 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
104 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
105 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
106 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
107 pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
108 pIsValidLocaleName = (void*)GetProcAddress(hKernel32, "IsValidLocaleName");
111 #define eq(received, expected, label, type) \
112 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
113 (label), (received), (expected))
115 #define BUFFER_SIZE 128
116 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
118 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
119 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
120 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
121 "Expected '%s', got '%s'\n", Expected, buffer)
123 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
124 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
125 SetLastError(0xdeadbeef); buffer[0] = '\0'
126 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
127 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
129 #define NUO LOCALE_NOUSEROVERRIDE
131 static void test_GetLocaleInfoA(void)
133 int ret;
134 int len;
135 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
136 char buffer[BUFFER_SIZE];
137 char expected[BUFFER_SIZE];
138 DWORD val;
140 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
142 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
143 ok(ret, "got %d\n", ret);
144 ok(val == lcid, "got 0x%08x\n", val);
146 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
147 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
148 assumes SUBLANG_NEUTRAL for zh */
149 memset(expected, 0, COUNTOF(expected));
150 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
151 SetLastError(0xdeadbeef);
152 memset(buffer, 0, COUNTOF(buffer));
153 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
154 ok((ret == len) && !lstrcmpA(buffer, expected),
155 "got %d with '%s' (expected %d with '%s')\n",
156 ret, buffer, len, expected);
158 memset(expected, 0, COUNTOF(expected));
159 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
160 if (len) {
161 SetLastError(0xdeadbeef);
162 memset(buffer, 0, COUNTOF(buffer));
163 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
164 ok((ret == len) && !lstrcmpA(buffer, expected),
165 "got %d with '%s' (expected %d with '%s')\n",
166 ret, buffer, len, expected);
168 else
169 win_skip("LANG_ARABIC not installed\n");
171 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
172 memset(expected, 0, COUNTOF(expected));
173 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
174 SetLastError(0xdeadbeef);
175 memset(buffer, 0, COUNTOF(buffer));
176 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
177 ok((ret == len) && !lstrcmpA(buffer, expected),
178 "got %d with '%s' (expected %d with '%s')\n",
179 ret, buffer, len, expected);
182 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
183 * partially fill the buffer even if it is too short. See bug 637.
185 SetLastError(0xdeadbeef);
186 memset(buffer, 0, COUNTOF(buffer));
187 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
188 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
190 SetLastError(0xdeadbeef);
191 memset(buffer, 0, COUNTOF(buffer));
192 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
193 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
194 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
195 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
197 SetLastError(0xdeadbeef);
198 memset(buffer, 0, COUNTOF(buffer));
199 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
200 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
201 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
204 struct neutralsublang_name2_t {
205 WCHAR name[3];
206 WCHAR sname[15];
207 LCID lcid;
208 LCID lcid_broken;
209 WCHAR sname_broken[15];
210 int todo;
213 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
214 { {'a','r',0}, {'a','r','-','S','A',0},
215 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
216 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
217 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
218 { {'d','e',0}, {'d','e','-','D','E',0},
219 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
220 { {'e','n',0}, {'e','n','-','U','S',0},
221 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
222 { {'e','s',0}, {'e','s','-','E','S',0},
223 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
224 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
225 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
226 { {'g','a',0}, {'g','a','-','I','E',0},
227 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
228 { {'i','t',0}, {'i','t','-','I','T',0},
229 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
230 { {'m','s',0}, {'m','s','-','M','Y',0},
231 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
232 { {'n','l',0}, {'n','l','-','N','L',0},
233 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
234 { {'p','t',0}, {'p','t','-','B','R',0},
235 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
236 { {'s','r',0}, {'h','r','-','H','R',0},
237 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
238 { {'s','v',0}, {'s','v','-','S','E',0},
239 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
240 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
241 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
242 { {'z','h',0}, {'z','h','-','C','N',0},
243 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
244 { {0} }
247 static void test_GetLocaleInfoW(void)
249 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
250 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
251 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
252 WCHAR bufferW[80], buffer2W[80];
253 CHAR bufferA[80];
254 DWORD val;
255 DWORD ret;
256 INT i;
258 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
259 if (!ret) {
260 win_skip("GetLocaleInfoW() isn't implemented\n");
261 return;
264 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
265 ok(ret, "got %d\n", ret);
266 ok(val == lcid_en, "got 0x%08x\n", val);
268 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
269 if (ret)
271 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
272 'S','t','a','t','e','s',')',0};
273 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
274 static const WCHAR enW[] = {'e','n','-','U','S',0};
275 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
277 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
279 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
280 ok(ret, "got %d\n", ret);
281 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
283 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
284 ok(ret, "got %d\n", ret);
285 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
287 while (*ptr->name)
289 LANGID langid;
290 LCID lcid;
292 /* make neutral lcid */
293 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
294 lcid = MAKELCID(langid, SORT_DEFAULT);
296 val = 0;
297 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
298 if (ptr->todo & 0x1)
300 todo_wine
301 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
302 wine_dbgstr_w(ptr->name), val, ptr->lcid);
304 else
305 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
306 wine_dbgstr_w(ptr->name), val, ptr->lcid);
308 /* now check LOCALE_SNAME */
309 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
310 if (ptr->todo & 0x2)
311 todo_wine
312 ok(!lstrcmpW(bufferW, ptr->sname) ||
313 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
314 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
315 else
316 ok(!lstrcmpW(bufferW, ptr->sname) ||
317 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
318 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
319 ptr++;
322 else
323 win_skip("English neutral locale not supported\n");
325 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
326 if (!ret) {
327 win_skip("LANG_RUSSIAN locale data unavailable\n");
328 return;
330 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
331 bufferW, COUNTOF(bufferW));
332 if (!ret) {
333 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
334 return;
337 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
338 bufferA[0] = 'a';
339 SetLastError(0xdeadbeef);
340 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
341 bufferA, COUNTOF(bufferA));
342 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
343 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
344 ok(GetLastError() == ERROR_INVALID_FLAGS,
345 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
347 bufferW[0] = 'a';
348 SetLastError(0xdeadbeef);
349 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
350 bufferW, COUNTOF(bufferW));
351 ok(ret == 0,
352 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
353 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
354 ok(GetLastError() == ERROR_INVALID_FLAGS,
355 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
357 /* yes, test empty 13 month entry too */
358 for (i = 0; i < 12; i++) {
359 bufferW[0] = 0;
360 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
361 bufferW, COUNTOF(bufferW));
362 ok(ret, "Expected non zero result\n");
363 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
364 ret, lstrlenW(bufferW));
365 buffer2W[0] = 0;
366 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
367 buffer2W, COUNTOF(buffer2W));
368 ok(ret, "Expected non zero result\n");
369 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
370 ret, lstrlenW(buffer2W));
372 ok(lstrcmpW(bufferW, buffer2W) != 0,
373 "Expected genitive name to differ, got the same for month %d\n", i+1);
375 /* for locale without genitive names nominative returned in both cases */
376 bufferW[0] = 0;
377 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
378 bufferW, COUNTOF(bufferW));
379 ok(ret, "Expected non zero result\n");
380 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
381 ret, lstrlenW(bufferW));
382 buffer2W[0] = 0;
383 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
384 buffer2W, COUNTOF(buffer2W));
385 ok(ret, "Expected non zero result\n");
386 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
387 ret, lstrlenW(buffer2W));
389 ok(lstrcmpW(bufferW, buffer2W) == 0,
390 "Expected same names, got different for month %d\n", i+1);
394 static void test_GetTimeFormatA(void)
396 int ret;
397 SYSTEMTIME curtime;
398 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
399 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
401 memset(&curtime, 2, sizeof(SYSTEMTIME));
402 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
403 SetLastError(0xdeadbeef);
404 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
405 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
406 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
408 curtime.wHour = 8;
409 curtime.wMinute = 56;
410 curtime.wSecond = 13;
411 curtime.wMilliseconds = 22;
412 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
413 SetLastError(0xdeadbeef);
414 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
415 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
416 EXPECT_LENA; EXPECT_EQA;
418 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
419 SetLastError(0xdeadbeef);
420 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
421 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
422 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
424 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
425 SetLastError(0xdeadbeef);
426 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
427 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
428 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
430 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
431 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
432 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
433 EXPECT_LENA;
435 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
436 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
437 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
438 EXPECT_LENA; EXPECT_EQA;
440 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
441 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
442 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
443 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
444 "Expected '', got '%s'\n", buffer );
446 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
447 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
448 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
449 EXPECT_LENA; EXPECT_EQA;
451 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
452 strcpy(Expected, "8:56 AM");
453 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
454 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
455 EXPECT_LENA; EXPECT_EQA;
457 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
458 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
459 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
460 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
461 "Expected '8.@:56AM', got '%s'\n", buffer );
463 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
464 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
465 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
466 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
467 "Expected '', got '%s'\n", buffer );
469 STRINGSA("t/tt", "A/AM"); /* AM time marker */
470 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
472 EXPECT_LENA; EXPECT_EQA;
474 curtime.wHour = 13;
475 STRINGSA("t/tt", "P/PM"); /* PM time marker */
476 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
477 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
478 EXPECT_LENA; EXPECT_EQA;
480 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
481 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 EXPECT_LENA; EXPECT_EQA;
485 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
486 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
488 EXPECT_LENA; EXPECT_EQA;
490 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
491 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493 EXPECT_LENA; EXPECT_EQA;
495 curtime.wHour = 14; /* change this to 14 or 2pm */
496 curtime.wMinute = 5;
497 curtime.wSecond = 3;
498 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 */
499 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
500 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
501 EXPECT_LENA; EXPECT_EQA;
503 curtime.wHour = 0;
504 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
505 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
506 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
507 EXPECT_LENA; EXPECT_EQA;
509 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
510 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
512 EXPECT_LENA; EXPECT_EQA;
514 /* try to convert formatting strings with more than two letters
515 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
516 * NOTE: We expect any letter for which there is an upper case value
517 * we should see a replacement. For letters that DO NOT have
518 * upper case values we should see NO REPLACEMENT.
520 curtime.wHour = 8;
521 curtime.wMinute = 56;
522 curtime.wSecond = 13;
523 curtime.wMilliseconds = 22;
524 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
525 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
526 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
527 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
528 EXPECT_LENA; EXPECT_EQA;
530 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
531 strcpy(buffer, "text");
532 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
533 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
534 EXPECT_EQA;
536 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
537 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
538 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
539 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
540 EXPECT_LENA; EXPECT_EQA;
542 STRINGSA("'''", "'"); /* invalid quoted string */
543 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
545 EXPECT_LENA; EXPECT_EQA;
547 /* test that msdn suggested single quotation usage works as expected */
548 STRINGSA("''''", "'"); /* single quote mark */
549 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
550 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
551 EXPECT_LENA; EXPECT_EQA;
553 STRINGSA("''HHHHHH", "08"); /* Normal use */
554 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
555 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
556 EXPECT_LENA; EXPECT_EQA;
558 /* and test for normal use of the single quotation mark */
559 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
560 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 EXPECT_LENA; EXPECT_EQA;
564 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
565 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
567 EXPECT_LENA; EXPECT_EQA;
569 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
570 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
571 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
572 EXPECT_LENA; EXPECT_EQA;
574 curtime.wHour = 25;
575 STRINGSA("'123'tt", ""); /* Invalid time */
576 SetLastError(0xdeadbeef);
577 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
579 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
581 curtime.wHour = 12;
582 curtime.wMonth = 60; /* Invalid */
583 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
584 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
585 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
586 EXPECT_LENA; EXPECT_EQA;
589 static void test_GetDateFormatA(void)
591 int ret;
592 SYSTEMTIME curtime;
593 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
594 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
595 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
596 char Broken[BUFFER_SIZE];
597 char short_day[10], month[10], genitive_month[10];
599 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
600 STRINGSA("ddd',' MMM dd yy","");
601 SetLastError(0xdeadbeef);
602 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
603 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
604 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
606 curtime.wYear = 2002;
607 curtime.wMonth = 5;
608 curtime.wDay = 4;
609 curtime.wDayOfWeek = 3;
610 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
611 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
612 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
613 EXPECT_LENA; EXPECT_EQA;
615 /* Same as above but with LOCALE_NOUSEROVERRIDE */
616 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
617 SetLastError(0xdeadbeef);
618 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
619 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
620 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
621 EXPECT_EQA;
623 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
624 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
625 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
626 EXPECT_LENA; EXPECT_EQA;
628 curtime.wHour = 36; /* Invalid */
629 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
630 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
631 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
632 EXPECT_LENA; EXPECT_EQA;
634 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
635 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
636 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
637 EXPECT_EQA;
639 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
640 SetLastError(0xdeadbeef);
641 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
642 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
643 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
645 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
646 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
647 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
648 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
649 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
651 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
652 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
653 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
654 EXPECT_LENA; EXPECT_EQA;
656 /* test for expected DATE_YEARMONTH behavior with null format */
657 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
658 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
659 SetLastError(0xdeadbeef);
660 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
661 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
662 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
663 EXPECT_EQA;
665 /* Test that using invalid DATE_* flags results in the correct error */
666 /* and return values */
667 STRINGSA("m/d/y", ""); /* Invalid flags */
668 SetLastError(0xdeadbeef);
669 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
670 &curtime, input, buffer, COUNTOF(buffer));
671 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
672 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
674 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
675 if (!ret)
677 win_skip("LANG_RUSSIAN locale data unavailable\n");
678 return;
681 /* month part should be in genitive form */
682 strcpy(genitive_month, buffer + 2);
683 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
684 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
685 strcpy(month, buffer);
686 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
688 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
689 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
690 strcpy(short_day, buffer);
692 STRINGSA("dd MMMMddd dd", "");
693 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
694 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
695 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
696 EXPECT_EQA;
698 STRINGSA("MMMMddd dd", "");
699 sprintf(Expected, "%s%s 04", month, short_day);
700 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 EXPECT_EQA;
704 STRINGSA("MMMMddd", "");
705 sprintf(Expected, "%s%s", month, short_day);
706 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 EXPECT_EQA;
710 STRINGSA("MMMMdd", "");
711 sprintf(Expected, "%s04", genitive_month);
712 sprintf(Broken, "%s04", month);
713 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
715 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
716 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
717 "Expected '%s', got '%s'\n", Expected, buffer);
719 STRINGSA("MMMMdd ddd", "");
720 sprintf(Expected, "%s04 %s", genitive_month, short_day);
721 sprintf(Broken, "%s04 %s", month, short_day);
722 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
723 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
724 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
725 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
726 "Expected '%s', got '%s'\n", Expected, buffer);
728 STRINGSA("dd dddMMMM", "");
729 sprintf(Expected, "04 %s%s", short_day, month);
730 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
731 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
732 EXPECT_EQA;
734 STRINGSA("dd dddMMMM ddd MMMMdd", "");
735 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
736 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
737 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
738 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
739 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
740 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
741 "Expected '%s', got '%s'\n", Expected, buffer);
743 /* with literal part */
744 STRINGSA("ddd',' MMMM dd", "");
745 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
746 sprintf(Broken, "%s, %s 04", short_day, month);
747 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
748 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
749 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
750 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
751 "Expected '%s', got '%s'\n", Expected, buffer);
754 static void test_GetDateFormatW(void)
756 int ret;
757 SYSTEMTIME curtime;
758 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
759 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
761 STRINGSW("",""); /* If flags is not zero then format must be NULL */
762 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
763 input, buffer, COUNTOF(buffer));
764 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
766 win_skip("GetDateFormatW is not implemented\n");
767 return;
769 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
770 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
771 EXPECT_EQW;
773 STRINGSW("",""); /* NULL buffer, len > 0 */
774 SetLastError(0xdeadbeef);
775 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
776 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
777 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
779 STRINGSW("",""); /* NULL buffer, len == 0 */
780 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
781 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
782 EXPECT_LENW; EXPECT_EQW;
784 curtime.wYear = 2002;
785 curtime.wMonth = 10;
786 curtime.wDay = 23;
787 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
788 curtime.wHour = 65432; /* Invalid */
789 curtime.wMinute = 34512; /* Invalid */
790 curtime.wSecond = 65535; /* Invalid */
791 curtime.wMilliseconds = 12345;
792 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
793 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
794 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
795 EXPECT_LENW; EXPECT_EQW;
797 /* Limit tests */
799 curtime.wYear = 1601;
800 curtime.wMonth = 1;
801 curtime.wDay = 1;
802 curtime.wDayOfWeek = 0; /* Irrelevant */
803 curtime.wHour = 0;
804 curtime.wMinute = 0;
805 curtime.wSecond = 0;
806 curtime.wMilliseconds = 0;
807 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
808 SetLastError(0xdeadbeef);
809 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
810 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
811 EXPECT_LENW; EXPECT_EQW;
813 curtime.wYear = 1600;
814 curtime.wMonth = 12;
815 curtime.wDay = 31;
816 curtime.wDayOfWeek = 0; /* Irrelevant */
817 curtime.wHour = 23;
818 curtime.wMinute = 59;
819 curtime.wSecond = 59;
820 curtime.wMilliseconds = 999;
821 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
822 SetLastError(0xdeadbeef);
823 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
824 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
825 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
829 #define CY_POS_LEFT 0
830 #define CY_POS_RIGHT 1
831 #define CY_POS_LEFT_SPACE 2
832 #define CY_POS_RIGHT_SPACE 3
834 static void test_GetCurrencyFormatA(void)
836 static char szDot[] = { '.', '\0' };
837 static char szComma[] = { ',', '\0' };
838 static char szDollar[] = { '$', '\0' };
839 int ret;
840 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
841 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
842 CURRENCYFMTA format;
844 memset(&format, 0, sizeof(format));
846 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
847 SetLastError(0xdeadbeef);
848 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
849 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
850 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
852 STRINGSA("23,53",""); /* Invalid character --> Error */
853 SetLastError(0xdeadbeef);
854 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
855 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
856 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
858 STRINGSA("--",""); /* Double '-' --> Error */
859 SetLastError(0xdeadbeef);
860 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
861 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
862 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
864 STRINGSA("0-",""); /* Trailing '-' --> Error */
865 SetLastError(0xdeadbeef);
866 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
867 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
868 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
870 STRINGSA("0..",""); /* Double '.' --> Error */
871 SetLastError(0xdeadbeef);
872 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
873 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
874 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
876 STRINGSA(" 0.1",""); /* Leading space --> Error */
877 SetLastError(0xdeadbeef);
878 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
879 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
880 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
882 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
883 SetLastError(0xdeadbeef);
884 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
885 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
886 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
888 STRINGSA("2353",""); /* Format and flags given --> Error */
889 SetLastError(0xdeadbeef);
890 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
891 ok( !ret, "Expected ret == 0, got %d\n", ret);
892 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
893 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 STRINGSA("2353",""); /* Invalid format --> Error */
896 SetLastError(0xdeadbeef);
897 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
898 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
899 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
901 STRINGSA("2353","$2,353.00"); /* Valid number */
902 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
903 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
904 EXPECT_LENA; EXPECT_EQA;
906 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
907 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
908 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
909 EXPECT_LENA; EXPECT_EQA;
911 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
912 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
913 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
914 EXPECT_LENA; EXPECT_EQA;
916 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
917 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
918 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919 EXPECT_LENA; EXPECT_EQA;
921 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
922 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
923 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
924 EXPECT_LENA; EXPECT_EQA;
926 format.NumDigits = 0; /* No decimal separator */
927 format.LeadingZero = 0;
928 format.Grouping = 0; /* No grouping char */
929 format.NegativeOrder = 0;
930 format.PositiveOrder = CY_POS_LEFT;
931 format.lpDecimalSep = szDot;
932 format.lpThousandSep = szComma;
933 format.lpCurrencySymbol = szDollar;
935 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
936 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
937 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
938 EXPECT_LENA; EXPECT_EQA;
940 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
941 STRINGSA("2353","$2353.0");
942 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
943 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
944 EXPECT_LENA; EXPECT_EQA;
946 format.Grouping = 2; /* Group by 100's */
947 STRINGSA("2353","$23,53.0");
948 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
949 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
950 EXPECT_LENA; EXPECT_EQA;
952 STRINGSA("235","$235.0"); /* Grouping of a positive number */
953 format.Grouping = 3;
954 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
955 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
956 EXPECT_LENA; EXPECT_EQA;
958 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
959 format.NegativeOrder = 2;
960 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
961 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
962 EXPECT_LENA; EXPECT_EQA;
964 format.LeadingZero = 1; /* Always provide leading zero */
965 STRINGSA(".5","$0.5");
966 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
967 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
968 EXPECT_LENA; EXPECT_EQA;
970 format.PositiveOrder = CY_POS_RIGHT;
971 STRINGSA("1","1.0$");
972 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
973 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
974 EXPECT_LENA; EXPECT_EQA;
976 format.PositiveOrder = CY_POS_LEFT_SPACE;
977 STRINGSA("1","$ 1.0");
978 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
979 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
980 EXPECT_LENA; EXPECT_EQA;
982 format.PositiveOrder = CY_POS_RIGHT_SPACE;
983 STRINGSA("1","1.0 $");
984 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
985 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
986 EXPECT_LENA; EXPECT_EQA;
988 format.NegativeOrder = 0;
989 STRINGSA("-1","($1.0)");
990 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
991 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
992 EXPECT_LENA; EXPECT_EQA;
994 format.NegativeOrder = 1;
995 STRINGSA("-1","-$1.0");
996 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
997 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
998 EXPECT_LENA; EXPECT_EQA;
1000 format.NegativeOrder = 2;
1001 STRINGSA("-1","$-1.0");
1002 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1003 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1004 EXPECT_LENA; EXPECT_EQA;
1006 format.NegativeOrder = 3;
1007 STRINGSA("-1","$1.0-");
1008 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1009 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1010 EXPECT_LENA; EXPECT_EQA;
1012 format.NegativeOrder = 4;
1013 STRINGSA("-1","(1.0$)");
1014 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1015 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1016 EXPECT_LENA; EXPECT_EQA;
1018 format.NegativeOrder = 5;
1019 STRINGSA("-1","-1.0$");
1020 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1021 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1022 EXPECT_LENA; EXPECT_EQA;
1024 format.NegativeOrder = 6;
1025 STRINGSA("-1","1.0-$");
1026 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1027 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1028 EXPECT_LENA; EXPECT_EQA;
1030 format.NegativeOrder = 7;
1031 STRINGSA("-1","1.0$-");
1032 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1033 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1034 EXPECT_LENA; EXPECT_EQA;
1036 format.NegativeOrder = 8;
1037 STRINGSA("-1","-1.0 $");
1038 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1039 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1040 EXPECT_LENA; EXPECT_EQA;
1042 format.NegativeOrder = 9;
1043 STRINGSA("-1","-$ 1.0");
1044 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1045 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1046 EXPECT_LENA; EXPECT_EQA;
1048 format.NegativeOrder = 10;
1049 STRINGSA("-1","1.0 $-");
1050 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1051 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1052 EXPECT_LENA; EXPECT_EQA;
1054 format.NegativeOrder = 11;
1055 STRINGSA("-1","$ 1.0-");
1056 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1057 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1058 EXPECT_LENA; EXPECT_EQA;
1060 format.NegativeOrder = 12;
1061 STRINGSA("-1","$ -1.0");
1062 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1063 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064 EXPECT_LENA; EXPECT_EQA;
1066 format.NegativeOrder = 13;
1067 STRINGSA("-1","1.0- $");
1068 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1069 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1070 EXPECT_LENA; EXPECT_EQA;
1072 format.NegativeOrder = 14;
1073 STRINGSA("-1","($ 1.0)");
1074 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1075 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1076 EXPECT_LENA; EXPECT_EQA;
1078 format.NegativeOrder = 15;
1079 STRINGSA("-1","(1.0 $)");
1080 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1081 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1082 EXPECT_LENA; EXPECT_EQA;
1085 #define NEG_PARENS 0 /* "(1.1)" */
1086 #define NEG_LEFT 1 /* "-1.1" */
1087 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1088 #define NEG_RIGHT 3 /* "1.1-" */
1089 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1091 static void test_GetNumberFormatA(void)
1093 static char szDot[] = { '.', '\0' };
1094 static char szComma[] = { ',', '\0' };
1095 int ret;
1096 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1097 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1098 NUMBERFMTA format;
1100 memset(&format, 0, sizeof(format));
1102 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1103 SetLastError(0xdeadbeef);
1104 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1105 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1106 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1108 STRINGSA("23,53",""); /* Invalid character --> Error */
1109 SetLastError(0xdeadbeef);
1110 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1111 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1112 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1114 STRINGSA("--",""); /* Double '-' --> Error */
1115 SetLastError(0xdeadbeef);
1116 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1117 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1118 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1120 STRINGSA("0-",""); /* Trailing '-' --> Error */
1121 SetLastError(0xdeadbeef);
1122 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1123 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1124 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1126 STRINGSA("0..",""); /* Double '.' --> Error */
1127 SetLastError(0xdeadbeef);
1128 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1129 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1130 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1132 STRINGSA(" 0.1",""); /* Leading space --> Error */
1133 SetLastError(0xdeadbeef);
1134 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1135 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1136 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1138 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1139 SetLastError(0xdeadbeef);
1140 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1141 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1142 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1144 STRINGSA("2353",""); /* Format and flags given --> Error */
1145 SetLastError(0xdeadbeef);
1146 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1147 ok( !ret, "Expected ret == 0, got %d\n", ret);
1148 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1149 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1151 STRINGSA("2353",""); /* Invalid format --> Error */
1152 SetLastError(0xdeadbeef);
1153 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1154 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1155 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1157 STRINGSA("2353","2,353.00"); /* Valid number */
1158 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1159 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1160 EXPECT_LENA; EXPECT_EQA;
1162 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1163 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1164 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1165 EXPECT_LENA; EXPECT_EQA;
1167 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1168 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1169 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1170 EXPECT_LENA; EXPECT_EQA;
1172 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1173 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1174 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1175 EXPECT_LENA; EXPECT_EQA;
1177 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1178 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1179 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1180 EXPECT_LENA; EXPECT_EQA;
1182 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1183 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1184 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1185 EXPECT_LENA; EXPECT_EQA;
1187 format.NumDigits = 0; /* No decimal separator */
1188 format.LeadingZero = 0;
1189 format.Grouping = 0; /* No grouping char */
1190 format.NegativeOrder = 0;
1191 format.lpDecimalSep = szDot;
1192 format.lpThousandSep = szComma;
1194 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1195 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1196 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1197 EXPECT_LENA; EXPECT_EQA;
1199 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1200 STRINGSA("2353","2353.0");
1201 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1202 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1203 EXPECT_LENA; EXPECT_EQA;
1205 format.Grouping = 2; /* Group by 100's */
1206 STRINGSA("2353","23,53.0");
1207 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1208 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1209 EXPECT_LENA; EXPECT_EQA;
1211 STRINGSA("235","235.0"); /* Grouping of a positive number */
1212 format.Grouping = 3;
1213 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1214 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1215 EXPECT_LENA; EXPECT_EQA;
1217 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1218 format.NegativeOrder = NEG_LEFT;
1219 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1220 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1221 EXPECT_LENA; EXPECT_EQA;
1223 format.LeadingZero = 1; /* Always provide leading zero */
1224 STRINGSA(".5","0.5");
1225 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1226 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1227 EXPECT_LENA; EXPECT_EQA;
1229 format.NegativeOrder = NEG_PARENS;
1230 STRINGSA("-1","(1.0)");
1231 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1232 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1233 EXPECT_LENA; EXPECT_EQA;
1235 format.NegativeOrder = NEG_LEFT;
1236 STRINGSA("-1","-1.0");
1237 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1238 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1239 EXPECT_LENA; EXPECT_EQA;
1241 format.NegativeOrder = NEG_LEFT_SPACE;
1242 STRINGSA("-1","- 1.0");
1243 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1244 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1245 EXPECT_LENA; EXPECT_EQA;
1247 format.NegativeOrder = NEG_RIGHT;
1248 STRINGSA("-1","1.0-");
1249 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1250 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1251 EXPECT_LENA; EXPECT_EQA;
1253 format.NegativeOrder = NEG_RIGHT_SPACE;
1254 STRINGSA("-1","1.0 -");
1255 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1256 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1257 EXPECT_LENA; EXPECT_EQA;
1259 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1261 if (IsValidLocale(lcid, 0))
1263 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1264 Expected[3] = 160; /* Non breaking space */
1265 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1266 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1267 EXPECT_LENA; EXPECT_EQA;
1271 struct comparestringa_entry {
1272 LCID lcid;
1273 DWORD flags;
1274 const char *first;
1275 int first_len;
1276 const char *second;
1277 int second_len;
1278 int ret;
1281 static const struct comparestringa_entry comparestringa_data[] = {
1282 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1283 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1284 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1285 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1286 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1287 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1288 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1289 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1290 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1291 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1292 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1293 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1294 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1295 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1296 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1297 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1298 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1299 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1300 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1301 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1302 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1303 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1304 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1305 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1306 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1307 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1308 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1309 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1310 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1311 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1314 static void test_CompareStringA(void)
1316 int ret, i;
1317 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1319 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1321 const struct comparestringa_entry *entry = &comparestringa_data[i];
1323 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1324 entry->second, entry->second_len);
1325 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1328 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1329 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1331 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1332 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1334 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1335 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1337 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1338 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1340 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1342 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1343 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1345 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1346 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1348 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1349 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1351 /* test for CompareStringA flags */
1352 SetLastError(0xdeadbeef);
1353 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1354 ok(GetLastError() == ERROR_INVALID_FLAGS,
1355 "unexpected error code %d\n", GetLastError());
1356 ok(!ret, "CompareStringA must fail with invalid flag\n");
1358 SetLastError(0xdeadbeef);
1359 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1360 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1361 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1362 /* end of test for CompareStringA flags */
1364 ret = lstrcmpA("", "");
1365 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1367 ret = lstrcmpA(NULL, NULL);
1368 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1370 ret = lstrcmpA("", NULL);
1371 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1373 ret = lstrcmpA(NULL, "");
1374 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1377 if (0) { /* this requires collation table patch to make it MS compatible */
1378 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1379 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1381 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1382 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1384 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1385 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1387 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1388 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1390 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1391 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1393 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1394 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1396 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1397 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1399 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1400 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1402 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1403 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1405 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1406 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1408 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1409 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1411 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1412 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1416 /* WinXP handles embedded NULLs differently than earlier versions */
1417 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1418 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1420 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1421 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);
1423 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1424 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1426 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1427 ok(ret == CSTR_EQUAL || /* win2k */
1428 ret == CSTR_GREATER_THAN,
1429 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1431 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1432 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1434 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1435 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1437 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1438 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1440 ret = lstrcmpi("#", ".");
1441 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1443 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1445 /* \xB9 character lies between a and b */
1446 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1447 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1448 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1449 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1452 static void test_LCMapStringA(void)
1454 int ret, ret2;
1455 char buf[256], buf2[256];
1456 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1457 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1458 static const char symbols_stripped[] = "justateststring1";
1460 SetLastError(0xdeadbeef);
1461 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1462 lower_case, -1, buf, sizeof(buf));
1463 ok(ret == lstrlenA(lower_case) + 1,
1464 "ret %d, error %d, expected value %d\n",
1465 ret, GetLastError(), lstrlenA(lower_case) + 1);
1466 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1468 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1469 upper_case, -1, buf, sizeof(buf));
1470 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1471 ok(GetLastError() == ERROR_INVALID_FLAGS,
1472 "unexpected error code %d\n", GetLastError());
1474 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1475 upper_case, -1, buf, sizeof(buf));
1476 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1477 ok(GetLastError() == ERROR_INVALID_FLAGS,
1478 "unexpected error code %d\n", GetLastError());
1480 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1481 upper_case, -1, buf, sizeof(buf));
1482 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1483 ok(GetLastError() == ERROR_INVALID_FLAGS,
1484 "unexpected error code %d\n", GetLastError());
1486 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1487 upper_case, -1, buf, sizeof(buf));
1488 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1489 ok(GetLastError() == ERROR_INVALID_FLAGS,
1490 "unexpected error code %d\n", GetLastError());
1492 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1493 SetLastError(0xdeadbeef);
1494 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1495 upper_case, -1, buf, sizeof(buf));
1496 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1497 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1499 /* test LCMAP_LOWERCASE */
1500 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1501 upper_case, -1, buf, sizeof(buf));
1502 ok(ret == lstrlenA(upper_case) + 1,
1503 "ret %d, error %d, expected value %d\n",
1504 ret, GetLastError(), lstrlenA(upper_case) + 1);
1505 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1507 /* test LCMAP_UPPERCASE */
1508 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1509 lower_case, -1, buf, sizeof(buf));
1510 ok(ret == lstrlenA(lower_case) + 1,
1511 "ret %d, error %d, expected value %d\n",
1512 ret, GetLastError(), lstrlenA(lower_case) + 1);
1513 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1515 /* test buffer overflow */
1516 SetLastError(0xdeadbeef);
1517 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1518 lower_case, -1, buf, 4);
1519 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1520 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1522 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1523 lstrcpyA(buf, lower_case);
1524 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1525 buf, -1, buf, sizeof(buf));
1526 if (!ret) /* Win9x */
1527 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1528 else
1530 ok(ret == lstrlenA(lower_case) + 1,
1531 "ret %d, error %d, expected value %d\n",
1532 ret, GetLastError(), lstrlenA(lower_case) + 1);
1533 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1535 lstrcpyA(buf, upper_case);
1536 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1537 buf, -1, buf, sizeof(buf));
1538 if (!ret) /* Win9x */
1539 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1540 else
1542 ok(ret == lstrlenA(upper_case) + 1,
1543 "ret %d, error %d, expected value %d\n",
1544 ret, GetLastError(), lstrlenA(lower_case) + 1);
1545 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1548 /* otherwise src == dst should fail */
1549 SetLastError(0xdeadbeef);
1550 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1551 buf, 10, buf, sizeof(buf));
1552 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1553 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1554 "unexpected error code %d\n", GetLastError());
1555 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1557 /* test whether '\0' is always appended */
1558 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1559 upper_case, -1, buf, sizeof(buf));
1560 ok(ret, "LCMapStringA must succeed\n");
1561 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1562 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1563 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1564 ok(ret2, "LCMapStringA must succeed\n");
1565 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1566 ok(ret == ret2, "lengths of sort keys must be equal\n");
1567 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1569 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1570 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1571 upper_case, -1, buf, sizeof(buf));
1572 ok(ret, "LCMapStringA must succeed\n");
1573 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1574 lower_case, -1, buf2, sizeof(buf2));
1575 ok(ret2, "LCMapStringA must succeed\n");
1576 ok(ret == ret2, "lengths of sort keys must be equal\n");
1577 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1579 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1580 results from plain LCMAP_SORTKEY on Vista */
1582 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1583 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1584 lower_case, -1, buf, sizeof(buf));
1585 ok(ret, "LCMapStringA must succeed\n");
1586 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1587 symbols_stripped, -1, buf2, sizeof(buf2));
1588 ok(ret2, "LCMapStringA must succeed\n");
1589 ok(ret == ret2, "lengths of sort keys must be equal\n");
1590 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1592 /* test NORM_IGNORENONSPACE */
1593 lstrcpyA(buf, "foo");
1594 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1595 lower_case, -1, buf, sizeof(buf));
1596 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1597 lstrlenA(lower_case) + 1, ret);
1598 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1600 /* test NORM_IGNORESYMBOLS */
1601 lstrcpyA(buf, "foo");
1602 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1603 lower_case, -1, buf, sizeof(buf));
1604 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1605 lstrlenA(symbols_stripped) + 1, ret);
1606 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1608 /* test srclen = 0 */
1609 SetLastError(0xdeadbeef);
1610 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1611 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1612 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1613 "unexpected error code %d\n", GetLastError());
1616 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1618 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1620 int ret, ret2;
1621 WCHAR buf[256], buf2[256];
1622 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1624 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1625 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1626 if (broken(ret))
1627 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1628 else
1630 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1631 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1632 func_name, GetLastError());
1635 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1636 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1637 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1638 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1639 func_name, GetLastError());
1641 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1642 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1643 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1644 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1645 func_name, GetLastError());
1647 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1648 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1649 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1650 func_name);
1651 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1652 func_name, GetLastError());
1654 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1655 SetLastError(0xdeadbeef);
1656 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1657 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1658 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1659 func_name, GetLastError());
1660 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1662 /* test LCMAP_LOWERCASE */
1663 ret = func_ptr(LCMAP_LOWERCASE,
1664 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1665 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1666 ret, GetLastError(), lstrlenW(upper_case) + 1);
1667 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1669 /* test LCMAP_UPPERCASE */
1670 ret = func_ptr(LCMAP_UPPERCASE,
1671 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1672 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1673 ret, GetLastError(), lstrlenW(lower_case) + 1);
1674 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1676 /* test buffer overflow */
1677 SetLastError(0xdeadbeef);
1678 ret = func_ptr(LCMAP_UPPERCASE,
1679 lower_case, -1, buf, 4);
1680 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1681 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1683 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1684 lstrcpyW(buf, lower_case);
1685 ret = func_ptr(LCMAP_UPPERCASE,
1686 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1687 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1688 ret, GetLastError(), lstrlenW(lower_case) + 1);
1689 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1691 lstrcpyW(buf, upper_case);
1692 ret = func_ptr(LCMAP_LOWERCASE,
1693 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1694 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1695 ret, GetLastError(), lstrlenW(lower_case) + 1);
1696 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1698 /* otherwise src == dst should fail */
1699 SetLastError(0xdeadbeef);
1700 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1701 buf, 10, buf, sizeof(buf));
1702 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1703 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1704 "%s unexpected error code %d\n", func_name, GetLastError());
1705 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1707 /* test whether '\0' is always appended */
1708 ret = func_ptr(LCMAP_SORTKEY,
1709 upper_case, -1, buf, sizeof(buf));
1710 ok(ret, "%s func_ptr must succeed\n", func_name);
1711 ret2 = func_ptr(LCMAP_SORTKEY,
1712 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1713 ok(ret, "%s func_ptr must succeed\n", func_name);
1714 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1715 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1717 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1718 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1719 upper_case, -1, buf, sizeof(buf));
1720 ok(ret, "%s func_ptr must succeed\n", func_name);
1721 ret2 = func_ptr(LCMAP_SORTKEY,
1722 lower_case, -1, buf2, sizeof(buf2));
1723 ok(ret2, "%s func_ptr must succeed\n", func_name);
1724 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1725 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1727 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1728 results from plain LCMAP_SORTKEY on Vista */
1730 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1731 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1732 lower_case, -1, buf, sizeof(buf));
1733 ok(ret, "%s func_ptr must succeed\n", func_name);
1734 ret2 = func_ptr(LCMAP_SORTKEY,
1735 symbols_stripped, -1, buf2, sizeof(buf2));
1736 ok(ret2, "%s func_ptr must succeed\n", func_name);
1737 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1738 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1740 /* test NORM_IGNORENONSPACE */
1741 lstrcpyW(buf, fooW);
1742 ret = func_ptr(NORM_IGNORENONSPACE,
1743 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1744 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1745 lstrlenW(lower_case) + 1, ret);
1746 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1748 /* test NORM_IGNORESYMBOLS */
1749 lstrcpyW(buf, fooW);
1750 ret = func_ptr(NORM_IGNORESYMBOLS,
1751 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1752 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1753 lstrlenW(symbols_stripped) + 1, ret);
1754 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1756 /* test srclen = 0 */
1757 SetLastError(0xdeadbeef);
1758 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1759 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1761 "%s unexpected error code %d\n", func_name, GetLastError());
1764 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1766 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1769 static void test_LCMapStringW(void)
1771 int ret;
1772 WCHAR buf[256];
1774 trace("testing LCMapStringW\n");
1776 SetLastError(0xdeadbeef);
1777 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1778 todo_wine {
1779 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1780 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1783 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1786 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1788 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1791 static void test_LCMapStringEx(void)
1793 int ret;
1794 WCHAR buf[256];
1796 if (!pLCMapStringEx)
1798 win_skip( "LCMapStringEx not available\n" );
1799 return;
1802 trace("testing LCMapStringEx\n");
1804 SetLastError(0xdeadbeef);
1805 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
1806 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1807 todo_wine {
1808 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1809 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1812 /* test reserved parameters */
1813 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1814 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1815 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1816 ret, GetLastError(), lstrlenW(upper_case) + 1);
1817 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1819 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1820 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1821 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1822 ret, GetLastError(), lstrlenW(upper_case) + 1);
1823 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1825 /* crashes on native */
1826 if(0)
1827 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1828 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1830 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1833 struct neutralsublang_name_t {
1834 WCHAR name[3];
1835 LCID lcid;
1836 int todo;
1839 static const struct neutralsublang_name_t neutralsublang_names[] = {
1840 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1841 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1842 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1843 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1844 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1845 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1846 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1847 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1848 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1849 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1850 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1851 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1852 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1853 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1854 { {0} }
1857 static void test_LocaleNameToLCID(void)
1859 LCID lcid;
1860 INT ret;
1861 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1862 static const WCHAR enW[] = {'e','n',0};
1864 if (!pLocaleNameToLCID)
1866 win_skip( "LocaleNameToLCID not available\n" );
1867 return;
1870 /* special cases */
1871 buffer[0] = 0;
1872 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1873 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1874 "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1875 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1876 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1877 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1879 buffer[0] = 0;
1880 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1881 todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1882 "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1883 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1884 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1885 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1887 buffer[0] = 0;
1888 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1889 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1890 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1891 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1892 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1894 /* bad name */
1895 lcid = pLocaleNameToLCID(fooW, 0);
1896 todo_wine ok(lcid == 0, "got 0x%04x\n", lcid);
1898 /* english neutral name */
1899 lcid = pLocaleNameToLCID(enW, 0);
1900 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1901 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1902 if (lcid)
1904 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1906 while (*ptr->name)
1908 lcid = pLocaleNameToLCID(ptr->name, 0);
1909 if (ptr->todo)
1910 todo_wine
1911 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1912 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1913 else
1914 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1915 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1916 ptr++;
1921 /* this requires collation table patch to make it MS compatible */
1922 static const char * const strings_sorted[] =
1924 "'",
1925 "-",
1926 "!",
1927 "\"",
1928 ".",
1929 ":",
1930 "\\",
1931 "_",
1932 "`",
1933 "{",
1934 "}",
1935 "+",
1936 "0",
1937 "1",
1938 "2",
1939 "3",
1940 "4",
1941 "5",
1942 "6",
1943 "7",
1944 "8",
1945 "9",
1946 "a",
1947 "A",
1948 "b",
1949 "B",
1950 "c",
1954 static const char * const strings[] =
1956 "C",
1957 "\"",
1958 "9",
1959 "'",
1960 "}",
1961 "-",
1962 "7",
1963 "+",
1964 "`",
1965 "1",
1966 "a",
1967 "5",
1968 "\\",
1969 "8",
1970 "B",
1971 "3",
1972 "_",
1973 "6",
1974 "{",
1975 "2",
1976 "c",
1977 "4",
1978 "!",
1979 "0",
1980 "A",
1981 ":",
1982 "b",
1986 static int compare_string1(const void *e1, const void *e2)
1988 const char *s1 = *(const char *const *)e1;
1989 const char *s2 = *(const char *const *)e2;
1991 return lstrcmpA(s1, s2);
1994 static int compare_string2(const void *e1, const void *e2)
1996 const char *s1 = *(const char *const *)e1;
1997 const char *s2 = *(const char *const *)e2;
1999 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2002 static int compare_string3(const void *e1, const void *e2)
2004 const char *s1 = *(const char *const *)e1;
2005 const char *s2 = *(const char *const *)e2;
2006 char key1[256], key2[256];
2008 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2009 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2010 return strcmp(key1, key2);
2013 static void test_sorting(void)
2015 char buf[256];
2016 char **str_buf = (char **)buf;
2017 int i;
2019 assert(sizeof(buf) >= sizeof(strings));
2021 /* 1. sort using lstrcmpA */
2022 memcpy(buf, strings, sizeof(strings));
2023 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2024 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2026 ok(!strcmp(strings_sorted[i], str_buf[i]),
2027 "qsort using lstrcmpA failed for element %d\n", i);
2029 /* 2. sort using CompareStringA */
2030 memcpy(buf, strings, sizeof(strings));
2031 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2032 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2034 ok(!strcmp(strings_sorted[i], str_buf[i]),
2035 "qsort using CompareStringA failed for element %d\n", i);
2037 /* 3. sort using sort keys */
2038 memcpy(buf, strings, sizeof(strings));
2039 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2040 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2042 ok(!strcmp(strings_sorted[i], str_buf[i]),
2043 "qsort using sort keys failed for element %d\n", i);
2047 static void test_FoldStringA(void)
2049 int ret, i, j;
2050 BOOL is_special;
2051 char src[256], dst[256];
2052 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2053 static const char digits_dst[] = { '1','2','3','\0' };
2054 static const char composite_src[] =
2056 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2057 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2058 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2059 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2060 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2061 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2062 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2063 0xfb,0xfc,0xfd,0xff,'\0'
2065 static const char composite_dst[] =
2067 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2068 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2069 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2070 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2071 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2072 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2073 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2074 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2075 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2076 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2077 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2078 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2079 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2080 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2081 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2083 static const char composite_dst_alt[] =
2085 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2086 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2087 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2088 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2089 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2090 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2091 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2092 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2093 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2094 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2095 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2096 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2097 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2098 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2099 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2101 static const char ligatures_src[] =
2103 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2105 static const char ligatures_dst[] =
2107 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2109 static const struct special
2111 char src;
2112 char dst[4];
2113 } foldczone_special[] =
2115 /* src dst */
2116 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2117 { 0x98, { 0x20, 0x7e, 0x00 } },
2118 { 0x99, { 0x54, 0x4d, 0x00 } },
2119 { 0xa0, { 0x20, 0x00 } },
2120 { 0xa8, { 0x20, 0xa8, 0x00 } },
2121 { 0xaa, { 0x61, 0x00 } },
2122 { 0xaf, { 0x20, 0xaf, 0x00 } },
2123 { 0xb2, { 0x32, 0x00 } },
2124 { 0xb3, { 0x33, 0x00 } },
2125 { 0xb4, { 0x20, 0xb4, 0x00 } },
2126 { 0xb8, { 0x20, 0xb8, 0x00 } },
2127 { 0xb9, { 0x31, 0x00 } },
2128 { 0xba, { 0x6f, 0x00 } },
2129 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2130 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2131 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2132 { 0x00 }
2135 if (!pFoldStringA)
2136 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2138 /* these tests are locale specific */
2139 if (GetACP() != 1252)
2141 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2142 return;
2145 /* MAP_FOLDDIGITS */
2146 SetLastError(0);
2147 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2148 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2150 win_skip("FoldStringA is not implemented\n");
2151 return;
2153 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2154 ok(strcmp(dst, digits_dst) == 0,
2155 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2156 for (i = 1; i < 256; i++)
2158 if (!strchr(digits_src, i))
2160 src[0] = i;
2161 src[1] = '\0';
2162 SetLastError(0);
2163 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2164 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2165 ok(dst[0] == src[0],
2166 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2170 /* MAP_EXPAND_LIGATURES */
2171 SetLastError(0);
2172 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2173 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2174 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2175 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2176 ok(strcmp(dst, ligatures_dst) == 0,
2177 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2178 for (i = 1; i < 256; i++)
2180 if (!strchr(ligatures_src, i))
2182 src[0] = i;
2183 src[1] = '\0';
2184 SetLastError(0);
2185 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2186 if (ret == 3)
2188 /* Vista */
2189 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2190 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2191 "Got %s for %d\n", dst, i);
2193 else
2195 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2196 ok(dst[0] == src[0],
2197 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2203 /* MAP_COMPOSITE */
2204 SetLastError(0);
2205 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2206 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2207 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2208 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2209 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2211 for (i = 1; i < 256; i++)
2213 if (!strchr(composite_src, i))
2215 src[0] = i;
2216 src[1] = '\0';
2217 SetLastError(0);
2218 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2219 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2220 ok(dst[0] == src[0],
2221 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2222 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2226 /* MAP_FOLDCZONE */
2227 for (i = 1; i < 256; i++)
2229 src[0] = i;
2230 src[1] = '\0';
2231 SetLastError(0);
2232 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2233 is_special = FALSE;
2234 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2236 if (foldczone_special[j].src == src[0])
2238 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2239 "Expected ret == 2 or %d, got %d, error %d\n",
2240 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2241 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2242 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2243 (unsigned char)src[0]);
2244 is_special = TRUE;
2247 if (! is_special)
2249 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2250 ok(src[0] == dst[0],
2251 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2252 (unsigned char)src[0], (unsigned char)dst[0]);
2256 /* MAP_PRECOMPOSED */
2257 for (i = 1; i < 256; i++)
2259 src[0] = i;
2260 src[1] = '\0';
2261 SetLastError(0);
2262 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2263 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2264 ok(src[0] == dst[0],
2265 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2266 (unsigned char)src[0], (unsigned char)dst[0]);
2270 static void test_FoldStringW(void)
2272 int ret;
2273 unsigned int i, j;
2274 WCHAR src[256], dst[256], ch, prev_ch = 1;
2275 static const DWORD badFlags[] =
2278 MAP_PRECOMPOSED|MAP_COMPOSITE,
2279 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2280 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2282 /* Ranges of digits 0-9 : Must be sorted! */
2283 static const WCHAR digitRanges[] =
2285 0x0030, /* '0'-'9' */
2286 0x0660, /* Eastern Arabic */
2287 0x06F0, /* Arabic - Hindu */
2288 0x0966, /* Devengari */
2289 0x09E6, /* Bengalii */
2290 0x0A66, /* Gurmukhi */
2291 0x0AE6, /* Gujarati */
2292 0x0B66, /* Oriya */
2293 0x0BE6, /* Tamil - No 0 */
2294 0x0C66, /* Telugu */
2295 0x0CE6, /* Kannada */
2296 0x0D66, /* Maylayalam */
2297 0x0E50, /* Thai */
2298 0x0ED0, /* Laos */
2299 0x0F29, /* Tibet - 0 is out of sequence */
2300 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2301 0x2080, /* Subscript */
2302 0x245F, /* Circled - 0 is out of sequence */
2303 0x2473, /* Bracketed */
2304 0x2487, /* Full stop */
2305 0x2775, /* Inverted circled - No 0 */
2306 0x277F, /* Patterned circled - No 0 */
2307 0x2789, /* Inverted Patterned circled - No 0 */
2308 0x3020, /* Hangzhou */
2309 0xff10, /* Pliene chasse (?) */
2310 0xffff /* Terminator */
2312 /* Digits which are represented, but out of sequence */
2313 static const WCHAR outOfSequenceDigits[] =
2315 0xB9, /* Superscript 1 */
2316 0xB2, /* Superscript 2 */
2317 0xB3, /* Superscript 3 */
2318 0x0F33, /* Tibetan half zero */
2319 0x24EA, /* Circled 0 */
2320 0x3007, /* Ideographic number zero */
2321 '\0' /* Terminator */
2323 /* Digits in digitRanges for which no representation is available */
2324 static const WCHAR noDigitAvailable[] =
2326 0x0BE6, /* No Tamil 0 */
2327 0x0F29, /* No Tibetan half zero (out of sequence) */
2328 0x2473, /* No Bracketed 0 */
2329 0x2487, /* No 0 Full stop */
2330 0x2775, /* No inverted circled 0 */
2331 0x277F, /* No patterned circled */
2332 0x2789, /* No inverted Patterned circled */
2333 0x3020, /* No Hangzhou 0 */
2334 '\0' /* Terminator */
2336 static const WCHAR foldczone_src[] =
2338 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2339 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2341 static const WCHAR foldczone_dst[] =
2343 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2345 static const WCHAR foldczone_todo_src[] =
2347 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2349 static const WCHAR foldczone_todo_dst[] =
2351 0x3cb,0x1f0,' ','a',0
2353 static const WCHAR foldczone_todo_broken_dst[] =
2355 0x3cb,0x1f0,0xa0,0xaa,0
2357 static const WCHAR ligatures_src[] =
2359 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2360 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2361 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2362 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2363 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2364 0xfb04, 0xfb05, 0xfb06, '\0'
2366 static const WCHAR ligatures_dst[] =
2368 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2369 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2370 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2371 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2372 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2373 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2376 if (!pFoldStringW)
2378 win_skip("FoldStringW is not available\n");
2379 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2382 /* Invalid flag combinations */
2383 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2385 src[0] = dst[0] = '\0';
2386 SetLastError(0);
2387 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2388 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2390 win_skip("FoldStringW is not implemented\n");
2391 return;
2393 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2394 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2397 /* src & dst cannot be the same */
2398 SetLastError(0);
2399 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2400 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2401 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2403 /* src can't be NULL */
2404 SetLastError(0);
2405 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2406 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2407 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2409 /* srclen can't be 0 */
2410 SetLastError(0);
2411 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2412 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2413 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2415 /* dstlen can't be < 0 */
2416 SetLastError(0);
2417 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2418 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2419 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2421 /* Ret includes terminating NUL which is appended if srclen = -1 */
2422 SetLastError(0);
2423 src[0] = 'A';
2424 src[1] = '\0';
2425 dst[0] = '\0';
2426 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2427 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2428 ok(dst[0] == 'A' && dst[1] == '\0',
2429 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2430 'A', '\0', ret, dst[0], dst[1], GetLastError());
2432 /* If size is given, result is not NUL terminated */
2433 SetLastError(0);
2434 src[0] = 'A';
2435 src[1] = 'A';
2436 dst[0] = 'X';
2437 dst[1] = 'X';
2438 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2439 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2440 ok(dst[0] == 'A' && dst[1] == 'X',
2441 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2442 'A','X', ret, dst[0], dst[1], GetLastError());
2444 /* MAP_FOLDDIGITS */
2445 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2447 /* Check everything before this range */
2448 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2450 SetLastError(0);
2451 src[0] = ch;
2452 src[1] = dst[0] = '\0';
2453 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2454 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2456 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2457 /* Wine (correctly) maps all Unicode 4.0+ digits */
2458 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2459 (ch >= 0x1369 && ch <= 0x1371),
2460 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2463 if (digitRanges[j] == 0xffff)
2464 break; /* Finished the whole code point space */
2466 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2468 WCHAR c;
2470 /* Map out of sequence characters */
2471 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2472 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2473 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2474 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2475 else c = ch;
2476 SetLastError(0);
2477 src[0] = c;
2478 src[1] = dst[0] = '\0';
2479 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2480 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2482 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2483 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2484 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2485 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2486 strchrW(noDigitAvailable, c),
2487 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2488 ch, '0' + digitRanges[j] - ch, dst[0]);
2490 prev_ch = ch;
2493 /* MAP_FOLDCZONE */
2494 SetLastError(0);
2495 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2496 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2497 "Got %d, error %d\n", ret, GetLastError());
2498 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2499 "MAP_FOLDCZONE: Expanded incorrectly\n");
2501 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2502 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2503 "Got %d, error %d\n", ret, GetLastError());
2504 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2505 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2506 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2508 /* MAP_EXPAND_LIGATURES */
2509 SetLastError(0);
2510 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2511 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2512 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2513 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2514 "Got %d, error %d\n", ret, GetLastError());
2515 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2516 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2519 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2524 #define LCID_OK(l) \
2525 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2526 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2527 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2528 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2529 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2531 static void test_ConvertDefaultLocale(void)
2533 LCID lcid;
2535 /* Doesn't change lcid, even if non default sublang/sort used */
2536 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2537 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2538 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2539 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2541 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2542 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2543 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2544 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2545 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2547 /* Invariant language is not treated specially */
2548 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2550 /* User/system default languages alone are not mapped */
2551 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2552 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2554 /* Default lcids */
2555 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2556 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2557 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2560 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2561 DWORD dwFlags, LONG_PTR lParam)
2563 trace("%08x, %s, %s, %08x, %08lx\n",
2564 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2566 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2567 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2569 /* If lParam is one, we are calling with flags defaulted from 0 */
2570 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2571 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2573 return TRUE;
2576 static void test_EnumSystemLanguageGroupsA(void)
2578 BOOL ret;
2580 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2582 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2583 return;
2586 /* No enumeration proc */
2587 SetLastError(0);
2588 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2589 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2591 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2592 return;
2594 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2595 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2597 /* Invalid flags */
2598 SetLastError(0);
2599 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2600 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2602 /* No flags - defaults to LGRPID_INSTALLED */
2603 SetLastError(0xdeadbeef);
2604 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2605 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2607 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2608 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2611 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2613 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2614 return TRUE;
2617 static void test_EnumSystemLocalesEx(void)
2619 BOOL ret;
2621 if (!pEnumSystemLocalesEx)
2623 win_skip( "EnumSystemLocalesEx not available\n" );
2624 return;
2626 SetLastError( 0xdeadbeef );
2627 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2628 ok( !ret, "should have failed\n" );
2629 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2630 SetLastError( 0xdeadbeef );
2631 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2632 ok( ret, "failed err %u\n", GetLastError() );
2635 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2636 LONG_PTR lParam)
2638 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2640 /* invalid locale enumerated on some platforms */
2641 if (lcid == 0)
2642 return TRUE;
2644 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2645 "Enumerated grp %d not valid\n", lgrpid);
2646 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2647 "Enumerated grp locale %d not valid\n", lcid);
2648 return TRUE;
2651 static void test_EnumLanguageGroupLocalesA(void)
2653 BOOL ret;
2655 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2657 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2658 return;
2661 /* No enumeration proc */
2662 SetLastError(0);
2663 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2664 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2666 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2667 return;
2669 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2670 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2672 /* lgrpid too small */
2673 SetLastError(0);
2674 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2675 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2676 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2678 /* lgrpid too big */
2679 SetLastError(0);
2680 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2681 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2682 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2684 /* dwFlags is reserved */
2685 SetLastError(0);
2686 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2687 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2688 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2690 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2693 static void test_SetLocaleInfoA(void)
2695 BOOL bRet;
2696 LCID lcid = GetUserDefaultLCID();
2698 /* Null data */
2699 SetLastError(0);
2700 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2701 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2702 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2704 /* IDATE */
2705 SetLastError(0);
2706 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2707 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2708 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2710 /* ILDATE */
2711 SetLastError(0);
2712 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2713 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2714 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2717 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2719 trace("%s %08lx\n", value, lParam);
2720 return(TRUE);
2723 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2725 ok(!enumCount, "callback called again unexpected\n");
2726 enumCount++;
2727 return(FALSE);
2730 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2732 ok(0,"callback called unexpected\n");
2733 return(FALSE);
2736 static void test_EnumUILanguageA(void)
2738 BOOL ret;
2739 if (!pEnumUILanguagesA) {
2740 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2741 return;
2744 SetLastError(ERROR_SUCCESS);
2745 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2746 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2748 win_skip("EnumUILanguagesA is not implemented\n");
2749 return;
2751 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2753 enumCount = 0;
2754 SetLastError(ERROR_SUCCESS);
2755 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2758 SetLastError(ERROR_SUCCESS);
2759 ret = pEnumUILanguagesA(NULL, 0, 0);
2760 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2761 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2762 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2764 SetLastError(ERROR_SUCCESS);
2765 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2766 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2767 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2769 SetLastError(ERROR_SUCCESS);
2770 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2771 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2772 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2773 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2776 static char date_fmt_buf[1024];
2778 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2780 lstrcatA(date_fmt_buf, fmt);
2781 lstrcatA(date_fmt_buf, "\n");
2782 return TRUE;
2785 static void test_EnumDateFormatsA(void)
2787 char *p, buf[256];
2788 BOOL ret;
2789 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2791 trace("EnumDateFormatsA 0\n");
2792 date_fmt_buf[0] = 0;
2793 SetLastError(0xdeadbeef);
2794 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2795 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2797 win_skip("0 for dwFlags is not supported\n");
2799 else
2801 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2802 trace("%s\n", date_fmt_buf);
2803 /* test the 1st enumerated format */
2804 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2805 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2806 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2807 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2810 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2811 date_fmt_buf[0] = 0;
2812 SetLastError(0xdeadbeef);
2813 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2814 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2816 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2818 else
2820 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2821 trace("%s\n", date_fmt_buf);
2822 /* test the 1st enumerated format */
2823 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2824 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2825 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2826 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2829 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2830 date_fmt_buf[0] = 0;
2831 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2832 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2833 trace("%s\n", date_fmt_buf);
2834 /* test the 1st enumerated format */
2835 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2836 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2837 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2838 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2840 trace("EnumDateFormatsA DATE_LONGDATE\n");
2841 date_fmt_buf[0] = 0;
2842 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2843 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2844 trace("%s\n", date_fmt_buf);
2845 /* test the 1st enumerated format */
2846 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2847 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2848 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2849 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2851 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2852 date_fmt_buf[0] = 0;
2853 SetLastError(0xdeadbeef);
2854 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2855 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2857 skip("DATE_YEARMONTH is only present on W2K and later\n");
2858 return;
2860 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2861 trace("%s\n", date_fmt_buf);
2862 /* test the 1st enumerated format */
2863 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2864 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2865 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2866 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2867 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2870 static void test_EnumTimeFormatsA(void)
2872 char *p, buf[256];
2873 BOOL ret;
2874 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2876 trace("EnumTimeFormatsA 0\n");
2877 date_fmt_buf[0] = 0;
2878 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2879 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2880 trace("%s\n", date_fmt_buf);
2881 /* test the 1st enumerated format */
2882 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2883 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2884 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2885 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2887 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2888 date_fmt_buf[0] = 0;
2889 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2890 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2891 trace("%s\n", date_fmt_buf);
2892 /* test the 1st enumerated format */
2893 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2894 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2895 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2896 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2899 static void test_GetCPInfo(void)
2901 BOOL ret;
2902 CPINFO cpinfo;
2904 SetLastError(0xdeadbeef);
2905 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2906 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2907 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2908 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2910 SetLastError(0xdeadbeef);
2911 ret = GetCPInfo(CP_UTF7, &cpinfo);
2912 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2914 skip("Codepage CP_UTF7 is not installed/available\n");
2916 else
2918 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2919 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2920 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2921 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2922 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2923 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2926 SetLastError(0xdeadbeef);
2927 ret = GetCPInfo(CP_UTF8, &cpinfo);
2928 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2930 skip("Codepage CP_UTF8 is not installed/available\n");
2932 else
2934 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2935 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2936 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2937 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2938 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2939 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2940 "expected 4, got %u\n", cpinfo.MaxCharSize);
2945 * The CT_TYPE1 has varied over windows version.
2946 * The current target for correct behavior is windows 7.
2947 * There was a big shift between windows 2000 (first introduced) and windows Xp
2948 * Most of the old values below are from windows 2000.
2949 * A smaller subset of changes happened between windows Xp and Window vista/7
2951 static void test_GetStringTypeW(void)
2953 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2954 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2955 C1_SPACE | C1_BLANK | C1_DEFINED,
2956 C1_SPACE | C1_BLANK | C1_DEFINED,
2957 C1_SPACE | C1_BLANK | C1_DEFINED,
2958 C1_CNTRL | C1_BLANK | C1_DEFINED};
2959 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2960 C1_SPACE | C1_BLANK,
2961 C1_SPACE | C1_BLANK,
2962 C1_SPACE | C1_BLANK,
2963 C1_SPACE | C1_BLANK};
2965 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2967 /* Lu, Ll, Lt */
2968 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2969 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2970 C1_LOWER | C1_ALPHA,
2971 C1_UPPER | C1_LOWER | C1_ALPHA,
2972 C1_ALPHA};
2974 /* Sk, Sk, Mn, So, Me */
2975 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2976 /* Sc, Sm, No,*/
2977 0xffe0, 0xffe9, 0x2153};
2979 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2980 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2981 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2982 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2983 C1_ALPHA | C1_DEFINED,
2984 C1_CNTRL | C1_DEFINED,
2985 C1_PUNCT | C1_DEFINED,
2986 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2987 C1_ALPHA | C1_LOWER | C1_DEFINED,
2988 C1_ALPHA | C1_DEFINED };
2989 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2990 C1_ALPHA | C1_DEFINED,
2991 C1_CNTRL | C1_DEFINED,
2992 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2993 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2994 C1_ALPHA | C1_DEFINED,
2995 C1_DEFINED
2997 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2998 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3000 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3001 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3002 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3003 static const WCHAR lower_special[] = {0x2071, 0x207f};
3004 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3005 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3006 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3007 0xfff9, 0xfffa, 0xfffb};
3008 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3010 WORD types[20];
3011 int i;
3013 memset(types,0,sizeof(types));
3014 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3015 for (i = 0; i < 5; i++)
3016 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]);
3018 memset(types,0,sizeof(types));
3019 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3020 for (i = 0; i < 3; i++)
3021 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]));
3022 memset(types,0,sizeof(types));
3023 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3024 for (i = 0; i < 5; i++)
3025 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3027 memset(types,0,sizeof(types));
3028 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3029 for (i = 0; i < 8; i++)
3030 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);
3032 memset(types,0,sizeof(types));
3033 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3034 for (i = 0; i < 7; i++)
3035 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]);
3037 memset(types,0,sizeof(types));
3038 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3039 for (i = 0; i < 7; i++)
3040 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));
3043 memset(types,0,sizeof(types));
3044 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3045 for (i = 0; i < 12; i++)
3046 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);
3048 memset(types,0,sizeof(types));
3049 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3050 for (i = 0; i < 3; i++)
3051 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);
3053 memset(types,0,sizeof(types));
3054 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3055 for (i = 0; i < 2; i++)
3056 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);
3058 memset(types,0,sizeof(types));
3059 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3060 for (i = 0; i < 20; i++)
3061 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);
3063 memset(types,0,sizeof(types));
3064 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3065 for (i = 0; i < 3; i++)
3066 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 );
3069 static void test_IdnToNameprepUnicode(void)
3071 struct {
3072 DWORD in_len;
3073 const WCHAR in[64];
3074 DWORD ret;
3075 const WCHAR out[64];
3076 DWORD flags;
3077 DWORD err;
3078 DWORD todo;
3079 } test_data[] = {
3081 5, {'t','e','s','t',0},
3082 5, {'t','e','s','t',0},
3083 0, 0xdeadbeef
3086 3, {'a',0xe111,'b'},
3087 0, {0},
3088 0, ERROR_INVALID_NAME
3091 4, {'t',0,'e',0},
3092 0, {0},
3093 0, ERROR_INVALID_NAME
3096 1, {'T',0},
3097 1, {'T',0},
3098 0, 0xdeadbeef
3101 1, {0},
3102 0, {0},
3103 0, ERROR_INVALID_NAME
3106 6, {' ','-','/','[',']',0},
3107 6, {' ','-','/','[',']',0},
3108 0, 0xdeadbeef
3111 3, {'a','-','a'},
3112 3, {'a','-','a'},
3113 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3116 3, {'a','a','-'},
3117 0, {0},
3118 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3120 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3121 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3122 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3123 0, 0xdeadbeef, TRUE
3126 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3127 2, {'t',0},
3128 0, 0xdeadbeef
3130 { /* Another example of incorrectly working FoldString (composition) */
3131 2, {0x3b0, 0},
3132 2, {0x3b0, 0},
3133 0, 0xdeadbeef, TRUE
3136 2, {0x221, 0},
3137 0, {0},
3138 0, ERROR_NO_UNICODE_TRANSLATION
3141 2, {0x221, 0},
3142 2, {0x221, 0},
3143 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3146 5, {'a','.','.','a',0},
3147 0, {0},
3148 0, ERROR_INVALID_NAME
3151 3, {'a','.',0},
3152 3, {'a','.',0},
3153 0, 0xdeadbeef
3157 WCHAR buf[1024];
3158 DWORD i, ret, err;
3160 if (!pIdnToNameprepUnicode)
3162 win_skip("IdnToNameprepUnicode is not available\n");
3163 return;
3166 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3167 test_data[0].in_len, NULL, 0);
3168 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3170 SetLastError(0xdeadbeef);
3171 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3172 test_data[1].in_len, NULL, 0);
3173 err = GetLastError();
3174 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3175 ok(err == test_data[1].err, "err = %d\n", err);
3177 SetLastError(0xdeadbeef);
3178 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3179 buf, sizeof(buf)/sizeof(WCHAR));
3180 err = GetLastError();
3181 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3182 ok(err == 0xdeadbeef, "err = %d\n", err);
3184 SetLastError(0xdeadbeef);
3185 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3186 buf, sizeof(buf)/sizeof(WCHAR));
3187 err = GetLastError();
3188 ok(ret == 0, "ret = %d\n", ret);
3189 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3191 SetLastError(0xdeadbeef);
3192 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3193 buf, sizeof(buf)/sizeof(WCHAR));
3194 err = GetLastError();
3195 ok(ret == 0, "ret = %d\n", ret);
3196 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3198 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3199 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3200 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3202 SetLastError(0xdeadbeef);
3203 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3204 err = GetLastError();
3205 ok(ret == 0, "ret = %d\n", ret);
3206 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3208 SetLastError(0xdeadbeef);
3209 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3210 err = GetLastError();
3211 ok(ret == 0, "ret = %d\n", ret);
3212 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3214 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3216 SetLastError(0xdeadbeef);
3217 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3218 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3219 err = GetLastError();
3220 if(!test_data[i].todo) {
3221 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3222 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3223 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3224 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3225 }else {
3226 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3227 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3232 static void test_IdnToAscii(void)
3234 struct {
3235 DWORD in_len;
3236 const WCHAR in[64];
3237 DWORD ret;
3238 const WCHAR out[64];
3239 DWORD flags;
3240 DWORD err;
3241 } test_data[] = {
3243 5, {'T','e','s','t',0},
3244 5, {'T','e','s','t',0},
3245 0, 0xdeadbeef
3248 5, {'T','e',0x017c,'s','t',0},
3249 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3250 0, 0xdeadbeef
3253 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3254 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3255 0, 0xdeadbeef
3258 3, {0x0105,'.',0},
3259 9, {'x','n','-','-','2','d','a','.',0},
3260 0, 0xdeadbeef
3263 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3264 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3265 0, 0xdeadbeef
3268 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3269 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3270 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3271 0, 0xdeadbeef
3274 2, {0x221,0},
3275 8, {'x','n','-','-','6','l','a',0},
3276 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3280 WCHAR buf[1024];
3281 DWORD i, ret, err;
3283 if (!pIdnToAscii)
3285 win_skip("IdnToAscii is not available\n");
3286 return;
3289 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3291 SetLastError(0xdeadbeef);
3292 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3293 test_data[i].in_len, buf, sizeof(buf));
3294 err = GetLastError();
3295 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3296 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3297 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3298 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3302 static void test_IdnToUnicode(void)
3304 struct {
3305 DWORD in_len;
3306 const WCHAR in[64];
3307 DWORD ret;
3308 const WCHAR out[64];
3309 DWORD flags;
3310 DWORD err;
3311 } test_data[] = {
3313 5, {'T','e','s','.',0},
3314 5, {'T','e','s','.',0},
3315 0, 0xdeadbeef
3318 2, {0x105,0},
3319 0, {0},
3320 0, ERROR_INVALID_NAME
3323 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3324 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3325 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3326 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3327 0x05d1,0x05e8,0x05d9,0x05ea,0},
3328 0, 0xdeadbeef
3331 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3332 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3333 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3334 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3335 0, 0xdeadbeef
3338 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3339 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3340 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3341 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3342 0, {0},
3343 0, ERROR_INVALID_NAME
3346 8, {'x','n','-','-','6','l','a',0},
3347 2, {0x221,0},
3348 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3352 WCHAR buf[1024];
3353 DWORD i, ret, err;
3355 if (!pIdnToUnicode)
3357 win_skip("IdnToUnicode is not available\n");
3358 return;
3361 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3363 SetLastError(0xdeadbeef);
3364 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3365 test_data[i].in_len, buf, sizeof(buf));
3366 err = GetLastError();
3367 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3368 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3369 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3370 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3374 static void test_GetLocaleInfoEx(void)
3376 static const WCHAR enW[] = {'e','n',0};
3377 WCHAR bufferW[80];
3378 INT ret;
3380 if (!pGetLocaleInfoEx)
3382 win_skip("GetLocaleInfoEx not supported\n");
3383 return;
3386 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3387 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3388 if (ret)
3390 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3391 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3392 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3393 static const WCHAR usaW[] = {'U','S','A',0};
3394 static const WCHAR enuW[] = {'E','N','U',0};
3395 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3396 DWORD val;
3398 todo_wine
3399 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3401 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3402 ok(ret, "got %d\n", ret);
3403 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3405 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3406 ok(ret, "got %d\n", ret);
3407 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3409 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3410 ok(ret, "got %d\n", ret);
3411 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3413 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3414 ok(ret, "got %d\n", ret);
3415 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3417 bufferW[0] = 0;
3418 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3419 todo_wine
3420 ok(!ret, "got %d\n", ret);
3422 while (*ptr->name)
3424 val = 0;
3425 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3426 if (ptr->todo)
3427 todo_wine
3428 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3429 else
3430 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3431 bufferW[0] = 0;
3432 pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3433 todo_wine
3434 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3435 ptr++;
3440 static void test_IsValidLocaleName(void)
3442 static const WCHAR enW[] = {'e','n',0};
3443 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3444 static const WCHAR zzW[] = {'z','z',0};
3445 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3446 BOOL ret;
3448 if (!pIsValidLocaleName)
3450 win_skip("IsValidLocaleName not supported\n");
3451 return;
3454 ret = pIsValidLocaleName(enW);
3455 ok(ret, "IsValidLocaleName failed\n");
3456 ret = pIsValidLocaleName(enusW);
3457 ok(ret, "IsValidLocaleName failed\n");
3458 ret = pIsValidLocaleName(zzW);
3459 ok(!ret, "IsValidLocaleName should have failed\n");
3460 ret = pIsValidLocaleName(zzzzW);
3461 ok(!ret, "IsValidLocaleName should have failed\n");
3464 START_TEST(locale)
3466 InitFunctionPointers();
3469 test_EnumTimeFormatsA();
3470 test_EnumDateFormatsA();
3471 test_GetLocaleInfoA();
3472 test_GetLocaleInfoW();
3473 test_GetLocaleInfoEx();
3474 test_GetTimeFormatA();
3475 test_GetDateFormatA();
3476 test_GetDateFormatW();
3477 test_GetCurrencyFormatA(); /* Also tests the W version */
3478 test_GetNumberFormatA(); /* Also tests the W version */
3479 test_CompareStringA();
3480 test_LCMapStringA();
3481 test_LCMapStringW();
3482 test_LCMapStringEx();
3483 test_LocaleNameToLCID();
3484 test_FoldStringA();
3485 test_FoldStringW();
3486 test_ConvertDefaultLocale();
3487 test_EnumSystemLanguageGroupsA();
3488 test_EnumSystemLocalesEx();
3489 test_EnumLanguageGroupLocalesA();
3490 test_SetLocaleInfoA();
3491 test_EnumUILanguageA();
3492 test_GetCPInfo();
3493 test_GetStringTypeW();
3494 test_IdnToNameprepUnicode();
3495 test_IdnToAscii();
3496 test_IdnToUnicode();
3497 test_IsValidLocaleName();
3498 /* this requires collation table patch to make it MS compatible */
3499 if (0) test_sorting();