kernel32/tests: Added tests for OpenFileById.
[wine.git] / dlls / kernel32 / tests / locale.c
blob0225c2b91037e9450ef461cac5823ae29ee88091
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 SetLastError(0xdeadbeef);
1873 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1874 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1875 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
1876 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1877 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1878 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1880 buffer[0] = 0;
1881 SetLastError(0xdeadbeef);
1882 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1883 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1884 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
1885 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1886 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1887 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1889 buffer[0] = 0;
1890 SetLastError(0xdeadbeef);
1891 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1892 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1893 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1894 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1895 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1897 /* bad name */
1898 SetLastError(0xdeadbeef);
1899 lcid = pLocaleNameToLCID(fooW, 0);
1900 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1901 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
1903 /* english neutral name */
1904 lcid = pLocaleNameToLCID(enW, 0);
1905 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1906 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1907 if (lcid)
1909 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1911 while (*ptr->name)
1913 lcid = pLocaleNameToLCID(ptr->name, 0);
1914 if (ptr->todo)
1915 todo_wine
1916 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1917 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1918 else
1919 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1920 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1922 *buffer = 0;
1923 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
1924 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
1925 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
1926 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
1928 ptr++;
1933 /* this requires collation table patch to make it MS compatible */
1934 static const char * const strings_sorted[] =
1936 "'",
1937 "-",
1938 "!",
1939 "\"",
1940 ".",
1941 ":",
1942 "\\",
1943 "_",
1944 "`",
1945 "{",
1946 "}",
1947 "+",
1948 "0",
1949 "1",
1950 "2",
1951 "3",
1952 "4",
1953 "5",
1954 "6",
1955 "7",
1956 "8",
1957 "9",
1958 "a",
1959 "A",
1960 "b",
1961 "B",
1962 "c",
1966 static const char * const strings[] =
1968 "C",
1969 "\"",
1970 "9",
1971 "'",
1972 "}",
1973 "-",
1974 "7",
1975 "+",
1976 "`",
1977 "1",
1978 "a",
1979 "5",
1980 "\\",
1981 "8",
1982 "B",
1983 "3",
1984 "_",
1985 "6",
1986 "{",
1987 "2",
1988 "c",
1989 "4",
1990 "!",
1991 "0",
1992 "A",
1993 ":",
1994 "b",
1998 static int compare_string1(const void *e1, const void *e2)
2000 const char *s1 = *(const char *const *)e1;
2001 const char *s2 = *(const char *const *)e2;
2003 return lstrcmpA(s1, s2);
2006 static int compare_string2(const void *e1, const void *e2)
2008 const char *s1 = *(const char *const *)e1;
2009 const char *s2 = *(const char *const *)e2;
2011 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2014 static int compare_string3(const void *e1, const void *e2)
2016 const char *s1 = *(const char *const *)e1;
2017 const char *s2 = *(const char *const *)e2;
2018 char key1[256], key2[256];
2020 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2021 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2022 return strcmp(key1, key2);
2025 static void test_sorting(void)
2027 char buf[256];
2028 char **str_buf = (char **)buf;
2029 int i;
2031 assert(sizeof(buf) >= sizeof(strings));
2033 /* 1. sort using lstrcmpA */
2034 memcpy(buf, strings, sizeof(strings));
2035 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2036 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2038 ok(!strcmp(strings_sorted[i], str_buf[i]),
2039 "qsort using lstrcmpA failed for element %d\n", i);
2041 /* 2. sort using CompareStringA */
2042 memcpy(buf, strings, sizeof(strings));
2043 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2044 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2046 ok(!strcmp(strings_sorted[i], str_buf[i]),
2047 "qsort using CompareStringA failed for element %d\n", i);
2049 /* 3. sort using sort keys */
2050 memcpy(buf, strings, sizeof(strings));
2051 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2052 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2054 ok(!strcmp(strings_sorted[i], str_buf[i]),
2055 "qsort using sort keys failed for element %d\n", i);
2059 static void test_FoldStringA(void)
2061 int ret, i, j;
2062 BOOL is_special;
2063 char src[256], dst[256];
2064 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2065 static const char digits_dst[] = { '1','2','3','\0' };
2066 static const char composite_src[] =
2068 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2069 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2070 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2071 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2072 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2073 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2074 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2075 0xfb,0xfc,0xfd,0xff,'\0'
2077 static const char composite_dst[] =
2079 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2080 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2081 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2082 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2083 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2084 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2085 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2086 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2087 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2088 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2089 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2090 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2091 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2092 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2093 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2095 static const char composite_dst_alt[] =
2097 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2098 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2099 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2100 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2101 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2102 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2103 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2104 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2105 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2106 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2107 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2108 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2109 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2110 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2111 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2113 static const char ligatures_src[] =
2115 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2117 static const char ligatures_dst[] =
2119 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2121 static const struct special
2123 char src;
2124 char dst[4];
2125 } foldczone_special[] =
2127 /* src dst */
2128 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2129 { 0x98, { 0x20, 0x7e, 0x00 } },
2130 { 0x99, { 0x54, 0x4d, 0x00 } },
2131 { 0xa0, { 0x20, 0x00 } },
2132 { 0xa8, { 0x20, 0xa8, 0x00 } },
2133 { 0xaa, { 0x61, 0x00 } },
2134 { 0xaf, { 0x20, 0xaf, 0x00 } },
2135 { 0xb2, { 0x32, 0x00 } },
2136 { 0xb3, { 0x33, 0x00 } },
2137 { 0xb4, { 0x20, 0xb4, 0x00 } },
2138 { 0xb8, { 0x20, 0xb8, 0x00 } },
2139 { 0xb9, { 0x31, 0x00 } },
2140 { 0xba, { 0x6f, 0x00 } },
2141 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2142 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2143 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2144 { 0x00 }
2147 if (!pFoldStringA)
2148 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2150 /* these tests are locale specific */
2151 if (GetACP() != 1252)
2153 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2154 return;
2157 /* MAP_FOLDDIGITS */
2158 SetLastError(0);
2159 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2160 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2162 win_skip("FoldStringA is not implemented\n");
2163 return;
2165 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2166 ok(strcmp(dst, digits_dst) == 0,
2167 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2168 for (i = 1; i < 256; i++)
2170 if (!strchr(digits_src, i))
2172 src[0] = i;
2173 src[1] = '\0';
2174 SetLastError(0);
2175 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2176 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2177 ok(dst[0] == src[0],
2178 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2182 /* MAP_EXPAND_LIGATURES */
2183 SetLastError(0);
2184 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2185 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2186 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2187 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2188 ok(strcmp(dst, ligatures_dst) == 0,
2189 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2190 for (i = 1; i < 256; i++)
2192 if (!strchr(ligatures_src, i))
2194 src[0] = i;
2195 src[1] = '\0';
2196 SetLastError(0);
2197 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2198 if (ret == 3)
2200 /* Vista */
2201 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2202 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2203 "Got %s for %d\n", dst, i);
2205 else
2207 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2208 ok(dst[0] == src[0],
2209 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2215 /* MAP_COMPOSITE */
2216 SetLastError(0);
2217 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2218 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2219 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2220 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2221 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2223 for (i = 1; i < 256; i++)
2225 if (!strchr(composite_src, i))
2227 src[0] = i;
2228 src[1] = '\0';
2229 SetLastError(0);
2230 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2231 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2232 ok(dst[0] == src[0],
2233 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2234 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2238 /* MAP_FOLDCZONE */
2239 for (i = 1; i < 256; i++)
2241 src[0] = i;
2242 src[1] = '\0';
2243 SetLastError(0);
2244 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2245 is_special = FALSE;
2246 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2248 if (foldczone_special[j].src == src[0])
2250 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2251 "Expected ret == 2 or %d, got %d, error %d\n",
2252 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2253 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2254 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2255 (unsigned char)src[0]);
2256 is_special = TRUE;
2259 if (! is_special)
2261 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2262 ok(src[0] == dst[0],
2263 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2264 (unsigned char)src[0], (unsigned char)dst[0]);
2268 /* MAP_PRECOMPOSED */
2269 for (i = 1; i < 256; i++)
2271 src[0] = i;
2272 src[1] = '\0';
2273 SetLastError(0);
2274 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2275 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2276 ok(src[0] == dst[0],
2277 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2278 (unsigned char)src[0], (unsigned char)dst[0]);
2282 static void test_FoldStringW(void)
2284 int ret;
2285 unsigned int i, j;
2286 WCHAR src[256], dst[256], ch, prev_ch = 1;
2287 static const DWORD badFlags[] =
2290 MAP_PRECOMPOSED|MAP_COMPOSITE,
2291 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2292 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2294 /* Ranges of digits 0-9 : Must be sorted! */
2295 static const WCHAR digitRanges[] =
2297 0x0030, /* '0'-'9' */
2298 0x0660, /* Eastern Arabic */
2299 0x06F0, /* Arabic - Hindu */
2300 0x0966, /* Devengari */
2301 0x09E6, /* Bengalii */
2302 0x0A66, /* Gurmukhi */
2303 0x0AE6, /* Gujarati */
2304 0x0B66, /* Oriya */
2305 0x0BE6, /* Tamil - No 0 */
2306 0x0C66, /* Telugu */
2307 0x0CE6, /* Kannada */
2308 0x0D66, /* Maylayalam */
2309 0x0E50, /* Thai */
2310 0x0ED0, /* Laos */
2311 0x0F29, /* Tibet - 0 is out of sequence */
2312 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2313 0x2080, /* Subscript */
2314 0x245F, /* Circled - 0 is out of sequence */
2315 0x2473, /* Bracketed */
2316 0x2487, /* Full stop */
2317 0x2775, /* Inverted circled - No 0 */
2318 0x277F, /* Patterned circled - No 0 */
2319 0x2789, /* Inverted Patterned circled - No 0 */
2320 0x3020, /* Hangzhou */
2321 0xff10, /* Pliene chasse (?) */
2322 0xffff /* Terminator */
2324 /* Digits which are represented, but out of sequence */
2325 static const WCHAR outOfSequenceDigits[] =
2327 0xB9, /* Superscript 1 */
2328 0xB2, /* Superscript 2 */
2329 0xB3, /* Superscript 3 */
2330 0x0F33, /* Tibetan half zero */
2331 0x24EA, /* Circled 0 */
2332 0x3007, /* Ideographic number zero */
2333 '\0' /* Terminator */
2335 /* Digits in digitRanges for which no representation is available */
2336 static const WCHAR noDigitAvailable[] =
2338 0x0BE6, /* No Tamil 0 */
2339 0x0F29, /* No Tibetan half zero (out of sequence) */
2340 0x2473, /* No Bracketed 0 */
2341 0x2487, /* No 0 Full stop */
2342 0x2775, /* No inverted circled 0 */
2343 0x277F, /* No patterned circled */
2344 0x2789, /* No inverted Patterned circled */
2345 0x3020, /* No Hangzhou 0 */
2346 '\0' /* Terminator */
2348 static const WCHAR foldczone_src[] =
2350 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2351 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2353 static const WCHAR foldczone_dst[] =
2355 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2357 static const WCHAR foldczone_todo_src[] =
2359 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2361 static const WCHAR foldczone_todo_dst[] =
2363 0x3cb,0x1f0,' ','a',0
2365 static const WCHAR foldczone_todo_broken_dst[] =
2367 0x3cb,0x1f0,0xa0,0xaa,0
2369 static const WCHAR ligatures_src[] =
2371 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2372 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2373 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2374 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2375 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2376 0xfb04, 0xfb05, 0xfb06, '\0'
2378 static const WCHAR ligatures_dst[] =
2380 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2381 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2382 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2383 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2384 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2385 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2388 if (!pFoldStringW)
2390 win_skip("FoldStringW is not available\n");
2391 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2394 /* Invalid flag combinations */
2395 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2397 src[0] = dst[0] = '\0';
2398 SetLastError(0);
2399 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2400 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2402 win_skip("FoldStringW is not implemented\n");
2403 return;
2405 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2406 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2409 /* src & dst cannot be the same */
2410 SetLastError(0);
2411 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2412 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2413 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2415 /* src can't be NULL */
2416 SetLastError(0);
2417 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2418 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2419 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2421 /* srclen can't be 0 */
2422 SetLastError(0);
2423 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2424 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2425 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2427 /* dstlen can't be < 0 */
2428 SetLastError(0);
2429 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2430 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2431 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2433 /* Ret includes terminating NUL which is appended if srclen = -1 */
2434 SetLastError(0);
2435 src[0] = 'A';
2436 src[1] = '\0';
2437 dst[0] = '\0';
2438 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2439 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2440 ok(dst[0] == 'A' && dst[1] == '\0',
2441 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2442 'A', '\0', ret, dst[0], dst[1], GetLastError());
2444 /* If size is given, result is not NUL terminated */
2445 SetLastError(0);
2446 src[0] = 'A';
2447 src[1] = 'A';
2448 dst[0] = 'X';
2449 dst[1] = 'X';
2450 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2451 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2452 ok(dst[0] == 'A' && dst[1] == 'X',
2453 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2454 'A','X', ret, dst[0], dst[1], GetLastError());
2456 /* MAP_FOLDDIGITS */
2457 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2459 /* Check everything before this range */
2460 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2462 SetLastError(0);
2463 src[0] = ch;
2464 src[1] = dst[0] = '\0';
2465 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2466 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2468 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2469 /* Wine (correctly) maps all Unicode 4.0+ digits */
2470 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2471 (ch >= 0x1369 && ch <= 0x1371),
2472 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2475 if (digitRanges[j] == 0xffff)
2476 break; /* Finished the whole code point space */
2478 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2480 WCHAR c;
2482 /* Map out of sequence characters */
2483 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2484 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2485 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2486 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2487 else c = ch;
2488 SetLastError(0);
2489 src[0] = c;
2490 src[1] = dst[0] = '\0';
2491 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2492 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2494 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2495 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2496 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2497 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2498 strchrW(noDigitAvailable, c),
2499 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2500 ch, '0' + digitRanges[j] - ch, dst[0]);
2502 prev_ch = ch;
2505 /* MAP_FOLDCZONE */
2506 SetLastError(0);
2507 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2508 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2509 "Got %d, error %d\n", ret, GetLastError());
2510 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2511 "MAP_FOLDCZONE: Expanded incorrectly\n");
2513 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2514 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2515 "Got %d, error %d\n", ret, GetLastError());
2516 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2517 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2518 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2520 /* MAP_EXPAND_LIGATURES */
2521 SetLastError(0);
2522 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2523 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2524 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2525 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2526 "Got %d, error %d\n", ret, GetLastError());
2527 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2528 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2531 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2536 #define LCID_OK(l) \
2537 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2538 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2539 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2540 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2541 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2543 static void test_ConvertDefaultLocale(void)
2545 LCID lcid;
2547 /* Doesn't change lcid, even if non default sublang/sort used */
2548 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2549 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2550 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2551 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2553 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2554 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2555 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2556 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2557 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2559 /* Invariant language is not treated specially */
2560 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2562 /* User/system default languages alone are not mapped */
2563 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2564 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2566 /* Default lcids */
2567 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2568 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2569 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2572 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2573 DWORD dwFlags, LONG_PTR lParam)
2575 trace("%08x, %s, %s, %08x, %08lx\n",
2576 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2578 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2579 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2581 /* If lParam is one, we are calling with flags defaulted from 0 */
2582 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2583 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2585 return TRUE;
2588 static void test_EnumSystemLanguageGroupsA(void)
2590 BOOL ret;
2592 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2594 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2595 return;
2598 /* No enumeration proc */
2599 SetLastError(0);
2600 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2601 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2603 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2604 return;
2606 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2607 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2609 /* Invalid flags */
2610 SetLastError(0);
2611 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2612 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2614 /* No flags - defaults to LGRPID_INSTALLED */
2615 SetLastError(0xdeadbeef);
2616 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2617 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2619 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2620 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2623 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2625 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2626 return TRUE;
2629 static void test_EnumSystemLocalesEx(void)
2631 BOOL ret;
2633 if (!pEnumSystemLocalesEx)
2635 win_skip( "EnumSystemLocalesEx not available\n" );
2636 return;
2638 SetLastError( 0xdeadbeef );
2639 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2640 ok( !ret, "should have failed\n" );
2641 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2642 SetLastError( 0xdeadbeef );
2643 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2644 ok( ret, "failed err %u\n", GetLastError() );
2647 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2648 LONG_PTR lParam)
2650 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2652 /* invalid locale enumerated on some platforms */
2653 if (lcid == 0)
2654 return TRUE;
2656 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2657 "Enumerated grp %d not valid\n", lgrpid);
2658 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2659 "Enumerated grp locale %d not valid\n", lcid);
2660 return TRUE;
2663 static void test_EnumLanguageGroupLocalesA(void)
2665 BOOL ret;
2667 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2669 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2670 return;
2673 /* No enumeration proc */
2674 SetLastError(0);
2675 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2676 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2678 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2679 return;
2681 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2682 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2684 /* lgrpid too small */
2685 SetLastError(0);
2686 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2687 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2688 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2690 /* lgrpid too big */
2691 SetLastError(0);
2692 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2693 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2694 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2696 /* dwFlags is reserved */
2697 SetLastError(0);
2698 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2699 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2700 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2702 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2705 static void test_SetLocaleInfoA(void)
2707 BOOL bRet;
2708 LCID lcid = GetUserDefaultLCID();
2710 /* Null data */
2711 SetLastError(0);
2712 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2713 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2714 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2716 /* IDATE */
2717 SetLastError(0);
2718 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2719 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2720 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2722 /* ILDATE */
2723 SetLastError(0);
2724 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2725 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2726 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2729 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2731 trace("%s %08lx\n", value, lParam);
2732 return(TRUE);
2735 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2737 ok(!enumCount, "callback called again unexpected\n");
2738 enumCount++;
2739 return(FALSE);
2742 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2744 ok(0,"callback called unexpected\n");
2745 return(FALSE);
2748 static void test_EnumUILanguageA(void)
2750 BOOL ret;
2751 if (!pEnumUILanguagesA) {
2752 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2753 return;
2756 SetLastError(ERROR_SUCCESS);
2757 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2758 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2760 win_skip("EnumUILanguagesA is not implemented\n");
2761 return;
2763 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2765 enumCount = 0;
2766 SetLastError(ERROR_SUCCESS);
2767 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2768 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2770 SetLastError(ERROR_SUCCESS);
2771 ret = pEnumUILanguagesA(NULL, 0, 0);
2772 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2773 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2774 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2776 SetLastError(ERROR_SUCCESS);
2777 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2778 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2779 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2781 SetLastError(ERROR_SUCCESS);
2782 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2783 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2784 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2785 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2788 static char date_fmt_buf[1024];
2790 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2792 lstrcatA(date_fmt_buf, fmt);
2793 lstrcatA(date_fmt_buf, "\n");
2794 return TRUE;
2797 static void test_EnumDateFormatsA(void)
2799 char *p, buf[256];
2800 BOOL ret;
2801 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2803 trace("EnumDateFormatsA 0\n");
2804 date_fmt_buf[0] = 0;
2805 SetLastError(0xdeadbeef);
2806 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2807 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2809 win_skip("0 for dwFlags is not supported\n");
2811 else
2813 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2814 trace("%s\n", date_fmt_buf);
2815 /* test the 1st enumerated format */
2816 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2817 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2818 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2819 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2822 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2823 date_fmt_buf[0] = 0;
2824 SetLastError(0xdeadbeef);
2825 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2826 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2828 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2830 else
2832 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) 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);
2841 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2842 date_fmt_buf[0] = 0;
2843 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2844 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2845 trace("%s\n", date_fmt_buf);
2846 /* test the 1st enumerated format */
2847 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2848 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2849 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2850 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2852 trace("EnumDateFormatsA DATE_LONGDATE\n");
2853 date_fmt_buf[0] = 0;
2854 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2855 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2856 trace("%s\n", date_fmt_buf);
2857 /* test the 1st enumerated format */
2858 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2859 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2860 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2861 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2863 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2864 date_fmt_buf[0] = 0;
2865 SetLastError(0xdeadbeef);
2866 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2867 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2869 skip("DATE_YEARMONTH is only present on W2K and later\n");
2870 return;
2872 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2873 trace("%s\n", date_fmt_buf);
2874 /* test the 1st enumerated format */
2875 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2876 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2877 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2878 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2879 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2882 static void test_EnumTimeFormatsA(void)
2884 char *p, buf[256];
2885 BOOL ret;
2886 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2888 trace("EnumTimeFormatsA 0\n");
2889 date_fmt_buf[0] = 0;
2890 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2891 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2892 trace("%s\n", date_fmt_buf);
2893 /* test the 1st enumerated format */
2894 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2895 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2896 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2897 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2899 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2900 date_fmt_buf[0] = 0;
2901 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2902 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2903 trace("%s\n", date_fmt_buf);
2904 /* test the 1st enumerated format */
2905 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2906 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2907 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2908 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2911 static void test_GetCPInfo(void)
2913 BOOL ret;
2914 CPINFO cpinfo;
2916 SetLastError(0xdeadbeef);
2917 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2918 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2919 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2920 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2922 SetLastError(0xdeadbeef);
2923 ret = GetCPInfo(CP_UTF7, &cpinfo);
2924 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2926 skip("Codepage CP_UTF7 is not installed/available\n");
2928 else
2930 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2931 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2932 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2933 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2934 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2935 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2938 SetLastError(0xdeadbeef);
2939 ret = GetCPInfo(CP_UTF8, &cpinfo);
2940 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2942 skip("Codepage CP_UTF8 is not installed/available\n");
2944 else
2946 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2947 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2948 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2949 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2950 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2951 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2952 "expected 4, got %u\n", cpinfo.MaxCharSize);
2957 * The CT_TYPE1 has varied over windows version.
2958 * The current target for correct behavior is windows 7.
2959 * There was a big shift between windows 2000 (first introduced) and windows Xp
2960 * Most of the old values below are from windows 2000.
2961 * A smaller subset of changes happened between windows Xp and Window vista/7
2963 static void test_GetStringTypeW(void)
2965 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2966 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2967 C1_SPACE | C1_BLANK | C1_DEFINED,
2968 C1_SPACE | C1_BLANK | C1_DEFINED,
2969 C1_SPACE | C1_BLANK | C1_DEFINED,
2970 C1_CNTRL | C1_BLANK | C1_DEFINED};
2971 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2972 C1_SPACE | C1_BLANK,
2973 C1_SPACE | C1_BLANK,
2974 C1_SPACE | C1_BLANK,
2975 C1_SPACE | C1_BLANK};
2977 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2979 /* Lu, Ll, Lt */
2980 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2981 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2982 C1_LOWER | C1_ALPHA,
2983 C1_UPPER | C1_LOWER | C1_ALPHA,
2984 C1_ALPHA};
2986 /* Sk, Sk, Mn, So, Me */
2987 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2988 /* Sc, Sm, No,*/
2989 0xffe0, 0xffe9, 0x2153};
2991 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2992 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2993 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2994 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2995 C1_ALPHA | C1_DEFINED,
2996 C1_CNTRL | C1_DEFINED,
2997 C1_PUNCT | C1_DEFINED,
2998 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2999 C1_ALPHA | C1_LOWER | C1_DEFINED,
3000 C1_ALPHA | C1_DEFINED };
3001 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3002 C1_ALPHA | C1_DEFINED,
3003 C1_CNTRL | C1_DEFINED,
3004 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3005 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3006 C1_ALPHA | C1_DEFINED,
3007 C1_DEFINED
3009 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3010 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3012 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3013 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3014 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3015 static const WCHAR lower_special[] = {0x2071, 0x207f};
3016 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3017 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3018 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3019 0xfff9, 0xfffa, 0xfffb};
3020 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3022 WORD types[20];
3023 int i;
3025 memset(types,0,sizeof(types));
3026 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3027 for (i = 0; i < 5; i++)
3028 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]);
3030 memset(types,0,sizeof(types));
3031 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3032 for (i = 0; i < 3; i++)
3033 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]));
3034 memset(types,0,sizeof(types));
3035 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3036 for (i = 0; i < 5; i++)
3037 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3039 memset(types,0,sizeof(types));
3040 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3041 for (i = 0; i < 8; i++)
3042 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);
3044 memset(types,0,sizeof(types));
3045 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3046 for (i = 0; i < 7; i++)
3047 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]);
3049 memset(types,0,sizeof(types));
3050 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3051 for (i = 0; i < 7; i++)
3052 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));
3055 memset(types,0,sizeof(types));
3056 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3057 for (i = 0; i < 12; i++)
3058 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);
3060 memset(types,0,sizeof(types));
3061 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3062 for (i = 0; i < 3; i++)
3063 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);
3065 memset(types,0,sizeof(types));
3066 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3067 for (i = 0; i < 2; i++)
3068 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);
3070 memset(types,0,sizeof(types));
3071 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3072 for (i = 0; i < 20; i++)
3073 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);
3075 memset(types,0,sizeof(types));
3076 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3077 for (i = 0; i < 3; i++)
3078 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 );
3081 static void test_IdnToNameprepUnicode(void)
3083 struct {
3084 DWORD in_len;
3085 const WCHAR in[64];
3086 DWORD ret;
3087 const WCHAR out[64];
3088 DWORD flags;
3089 DWORD err;
3090 DWORD todo;
3091 } test_data[] = {
3093 5, {'t','e','s','t',0},
3094 5, {'t','e','s','t',0},
3095 0, 0xdeadbeef
3098 3, {'a',0xe111,'b'},
3099 0, {0},
3100 0, ERROR_INVALID_NAME
3103 4, {'t',0,'e',0},
3104 0, {0},
3105 0, ERROR_INVALID_NAME
3108 1, {'T',0},
3109 1, {'T',0},
3110 0, 0xdeadbeef
3113 1, {0},
3114 0, {0},
3115 0, ERROR_INVALID_NAME
3118 6, {' ','-','/','[',']',0},
3119 6, {' ','-','/','[',']',0},
3120 0, 0xdeadbeef
3123 3, {'a','-','a'},
3124 3, {'a','-','a'},
3125 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3128 3, {'a','a','-'},
3129 0, {0},
3130 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3132 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3133 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3134 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3135 0, 0xdeadbeef, TRUE
3138 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3139 2, {'t',0},
3140 0, 0xdeadbeef
3142 { /* Another example of incorrectly working FoldString (composition) */
3143 2, {0x3b0, 0},
3144 2, {0x3b0, 0},
3145 0, 0xdeadbeef, TRUE
3148 2, {0x221, 0},
3149 0, {0},
3150 0, ERROR_NO_UNICODE_TRANSLATION
3153 2, {0x221, 0},
3154 2, {0x221, 0},
3155 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3158 5, {'a','.','.','a',0},
3159 0, {0},
3160 0, ERROR_INVALID_NAME
3163 3, {'a','.',0},
3164 3, {'a','.',0},
3165 0, 0xdeadbeef
3169 WCHAR buf[1024];
3170 DWORD i, ret, err;
3172 if (!pIdnToNameprepUnicode)
3174 win_skip("IdnToNameprepUnicode is not available\n");
3175 return;
3178 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3179 test_data[0].in_len, NULL, 0);
3180 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3182 SetLastError(0xdeadbeef);
3183 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3184 test_data[1].in_len, NULL, 0);
3185 err = GetLastError();
3186 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3187 ok(err == test_data[1].err, "err = %d\n", err);
3189 SetLastError(0xdeadbeef);
3190 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3191 buf, sizeof(buf)/sizeof(WCHAR));
3192 err = GetLastError();
3193 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3194 ok(err == 0xdeadbeef, "err = %d\n", err);
3196 SetLastError(0xdeadbeef);
3197 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3198 buf, sizeof(buf)/sizeof(WCHAR));
3199 err = GetLastError();
3200 ok(ret == 0, "ret = %d\n", ret);
3201 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3203 SetLastError(0xdeadbeef);
3204 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3205 buf, sizeof(buf)/sizeof(WCHAR));
3206 err = GetLastError();
3207 ok(ret == 0, "ret = %d\n", ret);
3208 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3210 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3211 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3212 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3214 SetLastError(0xdeadbeef);
3215 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3216 err = GetLastError();
3217 ok(ret == 0, "ret = %d\n", ret);
3218 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3220 SetLastError(0xdeadbeef);
3221 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3222 err = GetLastError();
3223 ok(ret == 0, "ret = %d\n", ret);
3224 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3226 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3228 SetLastError(0xdeadbeef);
3229 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3230 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3231 err = GetLastError();
3232 if(!test_data[i].todo) {
3233 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3234 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3235 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3236 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3237 }else {
3238 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3239 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3244 static void test_IdnToAscii(void)
3246 struct {
3247 DWORD in_len;
3248 const WCHAR in[64];
3249 DWORD ret;
3250 const WCHAR out[64];
3251 DWORD flags;
3252 DWORD err;
3253 } test_data[] = {
3255 5, {'T','e','s','t',0},
3256 5, {'T','e','s','t',0},
3257 0, 0xdeadbeef
3260 5, {'T','e',0x017c,'s','t',0},
3261 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3262 0, 0xdeadbeef
3265 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3266 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3267 0, 0xdeadbeef
3270 3, {0x0105,'.',0},
3271 9, {'x','n','-','-','2','d','a','.',0},
3272 0, 0xdeadbeef
3275 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3276 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3277 0, 0xdeadbeef
3280 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3281 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3282 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3283 0, 0xdeadbeef
3286 2, {0x221,0},
3287 8, {'x','n','-','-','6','l','a',0},
3288 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3292 WCHAR buf[1024];
3293 DWORD i, ret, err;
3295 if (!pIdnToAscii)
3297 win_skip("IdnToAscii is not available\n");
3298 return;
3301 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3303 SetLastError(0xdeadbeef);
3304 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3305 test_data[i].in_len, buf, sizeof(buf));
3306 err = GetLastError();
3307 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3308 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3309 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3310 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3314 static void test_IdnToUnicode(void)
3316 struct {
3317 DWORD in_len;
3318 const WCHAR in[64];
3319 DWORD ret;
3320 const WCHAR out[64];
3321 DWORD flags;
3322 DWORD err;
3323 } test_data[] = {
3325 5, {'T','e','s','.',0},
3326 5, {'T','e','s','.',0},
3327 0, 0xdeadbeef
3330 2, {0x105,0},
3331 0, {0},
3332 0, ERROR_INVALID_NAME
3335 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3336 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3337 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3338 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3339 0x05d1,0x05e8,0x05d9,0x05ea,0},
3340 0, 0xdeadbeef
3343 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3344 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3345 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3346 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3347 0, 0xdeadbeef
3350 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3351 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3352 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3353 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3354 0, {0},
3355 0, ERROR_INVALID_NAME
3358 8, {'x','n','-','-','6','l','a',0},
3359 2, {0x221,0},
3360 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3364 WCHAR buf[1024];
3365 DWORD i, ret, err;
3367 if (!pIdnToUnicode)
3369 win_skip("IdnToUnicode is not available\n");
3370 return;
3373 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3375 SetLastError(0xdeadbeef);
3376 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3377 test_data[i].in_len, buf, sizeof(buf));
3378 err = GetLastError();
3379 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3380 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3381 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3382 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3386 static void test_GetLocaleInfoEx(void)
3388 static const WCHAR enW[] = {'e','n',0};
3389 WCHAR bufferW[80];
3390 INT ret;
3392 if (!pGetLocaleInfoEx)
3394 win_skip("GetLocaleInfoEx not supported\n");
3395 return;
3398 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3399 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3400 if (ret)
3402 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3403 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3404 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3405 static const WCHAR usaW[] = {'U','S','A',0};
3406 static const WCHAR enuW[] = {'E','N','U',0};
3407 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3408 DWORD val;
3410 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3411 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3413 SetLastError(0xdeadbeef);
3414 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
3415 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
3417 SetLastError(0xdeadbeef);
3418 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
3419 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
3421 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3422 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3423 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3425 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3426 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3427 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3429 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3430 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3431 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3433 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3434 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3435 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3437 bufferW[0] = 0;
3438 SetLastError(0xdeadbeef);
3439 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3440 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3442 while (*ptr->name)
3444 val = 0;
3445 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3446 if (ptr->todo)
3447 todo_wine
3448 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3449 else
3450 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3451 bufferW[0] = 0;
3452 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3453 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
3454 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3455 ptr++;
3460 static void test_IsValidLocaleName(void)
3462 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3463 static const WCHAR zzW[] = {'z','z',0};
3464 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3465 BOOL ret;
3467 if (!pIsValidLocaleName)
3469 win_skip("IsValidLocaleName not supported\n");
3470 return;
3473 ret = pIsValidLocaleName(enusW);
3474 ok(ret, "IsValidLocaleName failed\n");
3475 ret = pIsValidLocaleName(zzW);
3476 ok(!ret, "IsValidLocaleName should have failed\n");
3477 ret = pIsValidLocaleName(zzzzW);
3478 ok(!ret, "IsValidLocaleName should have failed\n");
3481 START_TEST(locale)
3483 InitFunctionPointers();
3486 test_EnumTimeFormatsA();
3487 test_EnumDateFormatsA();
3488 test_GetLocaleInfoA();
3489 test_GetLocaleInfoW();
3490 test_GetLocaleInfoEx();
3491 test_GetTimeFormatA();
3492 test_GetDateFormatA();
3493 test_GetDateFormatW();
3494 test_GetCurrencyFormatA(); /* Also tests the W version */
3495 test_GetNumberFormatA(); /* Also tests the W version */
3496 test_CompareStringA();
3497 test_LCMapStringA();
3498 test_LCMapStringW();
3499 test_LCMapStringEx();
3500 test_LocaleNameToLCID();
3501 test_FoldStringA();
3502 test_FoldStringW();
3503 test_ConvertDefaultLocale();
3504 test_EnumSystemLanguageGroupsA();
3505 test_EnumSystemLocalesEx();
3506 test_EnumLanguageGroupLocalesA();
3507 test_SetLocaleInfoA();
3508 test_EnumUILanguageA();
3509 test_GetCPInfo();
3510 test_GetStringTypeW();
3511 test_IdnToNameprepUnicode();
3512 test_IdnToAscii();
3513 test_IdnToUnicode();
3514 test_IsValidLocaleName();
3515 /* this requires collation table patch to make it MS compatible */
3516 if (0) test_sorting();