kernel32/tests: Skip tests on non-English systems.
[wine.git] / dlls / kernel32 / tests / locale.c
blobe9c83b8cc9f4c20fa5ba6610a7708f6a25265a6c
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);
90 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
92 static void InitFunctionPointers(void)
94 hKernel32 = GetModuleHandleA("kernel32");
95 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
96 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
97 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
98 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
99 pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
100 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
101 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
102 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
103 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
104 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
105 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
106 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
107 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
108 pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
109 pIsValidLocaleName = (void*)GetProcAddress(hKernel32, "IsValidLocaleName");
110 pCompareStringOrdinal = (void*)GetProcAddress(hKernel32, "CompareStringOrdinal");
113 #define eq(received, expected, label, type) \
114 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
115 (label), (received), (expected))
117 #define BUFFER_SIZE 128
118 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
120 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
121 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
122 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
123 "Expected '%s', got '%s'\n", Expected, buffer)
125 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
126 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
127 SetLastError(0xdeadbeef); buffer[0] = '\0'
128 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
129 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
131 #define NUO LOCALE_NOUSEROVERRIDE
133 static void test_GetLocaleInfoA(void)
135 int ret;
136 int len;
137 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
138 char buffer[BUFFER_SIZE];
139 char expected[BUFFER_SIZE];
140 DWORD val;
142 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
144 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
145 ok(ret, "got %d\n", ret);
146 ok(val == lcid, "got 0x%08x\n", val);
148 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
149 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
150 assumes SUBLANG_NEUTRAL for zh */
151 memset(expected, 0, COUNTOF(expected));
152 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
153 SetLastError(0xdeadbeef);
154 memset(buffer, 0, COUNTOF(buffer));
155 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
156 ok((ret == len) && !lstrcmpA(buffer, expected),
157 "got %d with '%s' (expected %d with '%s')\n",
158 ret, buffer, len, expected);
160 memset(expected, 0, COUNTOF(expected));
161 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
162 if (len) {
163 SetLastError(0xdeadbeef);
164 memset(buffer, 0, COUNTOF(buffer));
165 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
166 ok((ret == len) && !lstrcmpA(buffer, expected),
167 "got %d with '%s' (expected %d with '%s')\n",
168 ret, buffer, len, expected);
170 else
171 win_skip("LANG_ARABIC not installed\n");
173 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
174 memset(expected, 0, COUNTOF(expected));
175 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
176 SetLastError(0xdeadbeef);
177 memset(buffer, 0, COUNTOF(buffer));
178 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
179 ok((ret == len) && !lstrcmpA(buffer, expected),
180 "got %d with '%s' (expected %d with '%s')\n",
181 ret, buffer, len, expected);
184 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
185 * partially fill the buffer even if it is too short. See bug 637.
187 SetLastError(0xdeadbeef);
188 memset(buffer, 0, COUNTOF(buffer));
189 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
190 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
192 SetLastError(0xdeadbeef);
193 memset(buffer, 0, COUNTOF(buffer));
194 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
195 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
196 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
197 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
199 SetLastError(0xdeadbeef);
200 memset(buffer, 0, COUNTOF(buffer));
201 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
202 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
203 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
206 struct neutralsublang_name2_t {
207 WCHAR name[3];
208 WCHAR sname[15];
209 LCID lcid;
210 LCID lcid_broken;
211 WCHAR sname_broken[15];
212 int todo;
215 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
216 { {'a','r',0}, {'a','r','-','S','A',0},
217 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
218 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
219 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
220 { {'d','e',0}, {'d','e','-','D','E',0},
221 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
222 { {'e','n',0}, {'e','n','-','U','S',0},
223 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
224 { {'e','s',0}, {'e','s','-','E','S',0},
225 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
226 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
227 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
228 { {'g','a',0}, {'g','a','-','I','E',0},
229 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
230 { {'i','t',0}, {'i','t','-','I','T',0},
231 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
232 { {'m','s',0}, {'m','s','-','M','Y',0},
233 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
234 { {'n','l',0}, {'n','l','-','N','L',0},
235 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
236 { {'p','t',0}, {'p','t','-','B','R',0},
237 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
238 { {'s','r',0}, {'h','r','-','H','R',0},
239 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
240 { {'s','v',0}, {'s','v','-','S','E',0},
241 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
242 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
243 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
244 { {'z','h',0}, {'z','h','-','C','N',0},
245 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
246 { {0} }
249 static void test_GetLocaleInfoW(void)
251 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
252 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
253 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
254 WCHAR bufferW[80], buffer2W[80];
255 CHAR bufferA[80];
256 DWORD val;
257 DWORD ret;
258 INT i;
260 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
261 if (!ret) {
262 win_skip("GetLocaleInfoW() isn't implemented\n");
263 return;
266 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
267 ok(ret, "got %d\n", ret);
268 ok(val == lcid_en, "got 0x%08x\n", val);
270 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
271 if (ret)
273 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
274 'S','t','a','t','e','s',')',0};
275 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
276 static const WCHAR enW[] = {'e','n','-','U','S',0};
277 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
279 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
281 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
282 ok(ret, "got %d\n", ret);
283 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
284 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
286 skip("Non-English locale\n");
288 else
289 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
291 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
292 ok(ret, "got %d\n", ret);
293 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
294 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
296 skip("Non-English locale\n");
298 else
299 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
301 while (*ptr->name)
303 LANGID langid;
304 LCID lcid;
306 /* make neutral lcid */
307 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
308 lcid = MAKELCID(langid, SORT_DEFAULT);
310 val = 0;
311 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
312 if (ptr->todo & 0x1)
314 todo_wine
315 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
316 wine_dbgstr_w(ptr->name), val, ptr->lcid);
318 else
319 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
320 wine_dbgstr_w(ptr->name), val, ptr->lcid);
322 /* now check LOCALE_SNAME */
323 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
324 if (ptr->todo & 0x2)
325 todo_wine
326 ok(!lstrcmpW(bufferW, ptr->sname) ||
327 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
328 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
329 else
330 ok(!lstrcmpW(bufferW, ptr->sname) ||
331 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
332 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
333 ptr++;
336 else
337 win_skip("English neutral locale not supported\n");
339 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
340 if (!ret) {
341 win_skip("LANG_RUSSIAN locale data unavailable\n");
342 return;
344 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
345 bufferW, COUNTOF(bufferW));
346 if (!ret) {
347 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
348 return;
351 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
352 bufferA[0] = 'a';
353 SetLastError(0xdeadbeef);
354 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
355 bufferA, COUNTOF(bufferA));
356 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
357 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
358 ok(GetLastError() == ERROR_INVALID_FLAGS,
359 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
361 bufferW[0] = 'a';
362 SetLastError(0xdeadbeef);
363 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
364 bufferW, COUNTOF(bufferW));
365 ok(ret == 0,
366 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
367 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
368 ok(GetLastError() == ERROR_INVALID_FLAGS,
369 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
371 /* yes, test empty 13 month entry too */
372 for (i = 0; i < 12; i++) {
373 bufferW[0] = 0;
374 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
375 bufferW, COUNTOF(bufferW));
376 ok(ret, "Expected non zero result\n");
377 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
378 ret, lstrlenW(bufferW));
379 buffer2W[0] = 0;
380 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
381 buffer2W, COUNTOF(buffer2W));
382 ok(ret, "Expected non zero result\n");
383 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
384 ret, lstrlenW(buffer2W));
386 ok(lstrcmpW(bufferW, buffer2W) != 0,
387 "Expected genitive name to differ, got the same for month %d\n", i+1);
389 /* for locale without genitive names nominative returned in both cases */
390 bufferW[0] = 0;
391 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
392 bufferW, COUNTOF(bufferW));
393 ok(ret, "Expected non zero result\n");
394 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
395 ret, lstrlenW(bufferW));
396 buffer2W[0] = 0;
397 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
398 buffer2W, COUNTOF(buffer2W));
399 ok(ret, "Expected non zero result\n");
400 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
401 ret, lstrlenW(buffer2W));
403 ok(lstrcmpW(bufferW, buffer2W) == 0,
404 "Expected same names, got different for month %d\n", i+1);
408 static void test_GetTimeFormatA(void)
410 int ret;
411 SYSTEMTIME curtime;
412 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
413 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
415 memset(&curtime, 2, sizeof(SYSTEMTIME));
416 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
417 SetLastError(0xdeadbeef);
418 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
419 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
420 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
422 curtime.wHour = 8;
423 curtime.wMinute = 56;
424 curtime.wSecond = 13;
425 curtime.wMilliseconds = 22;
426 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
427 SetLastError(0xdeadbeef);
428 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
429 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
430 EXPECT_LENA; EXPECT_EQA;
432 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
433 SetLastError(0xdeadbeef);
434 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
435 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
436 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
438 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
439 SetLastError(0xdeadbeef);
440 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
441 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
442 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
444 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
445 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
446 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
447 EXPECT_LENA;
449 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
450 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
451 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
452 EXPECT_LENA; EXPECT_EQA;
454 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
455 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
456 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
457 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
458 "Expected '', got '%s'\n", buffer );
460 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
461 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
462 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
463 EXPECT_LENA; EXPECT_EQA;
465 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
466 strcpy(Expected, "8:56 AM");
467 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
468 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
469 EXPECT_LENA; EXPECT_EQA;
471 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
472 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
473 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
474 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
475 "Expected '8.@:56AM', got '%s'\n", buffer );
477 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
478 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
479 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
480 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
481 "Expected '', got '%s'\n", buffer );
483 STRINGSA("t/tt", "A/AM"); /* AM time marker */
484 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
485 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
486 EXPECT_LENA; EXPECT_EQA;
488 curtime.wHour = 13;
489 STRINGSA("t/tt", "P/PM"); /* PM time marker */
490 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
491 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
492 EXPECT_LENA; EXPECT_EQA;
494 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
495 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
496 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
497 EXPECT_LENA; EXPECT_EQA;
499 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
500 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
501 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
502 EXPECT_LENA; EXPECT_EQA;
504 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
505 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
506 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
507 EXPECT_LENA; EXPECT_EQA;
509 curtime.wHour = 14; /* change this to 14 or 2pm */
510 curtime.wMinute = 5;
511 curtime.wSecond = 3;
512 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 */
513 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
514 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
515 EXPECT_LENA; EXPECT_EQA;
517 curtime.wHour = 0;
518 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
519 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
520 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
521 EXPECT_LENA; EXPECT_EQA;
523 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
524 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
526 EXPECT_LENA; EXPECT_EQA;
528 /* try to convert formatting strings with more than two letters
529 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
530 * NOTE: We expect any letter for which there is an upper case value
531 * we should see a replacement. For letters that DO NOT have
532 * upper case values we should see NO REPLACEMENT.
534 curtime.wHour = 8;
535 curtime.wMinute = 56;
536 curtime.wSecond = 13;
537 curtime.wMilliseconds = 22;
538 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
539 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
540 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
541 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
542 EXPECT_LENA; EXPECT_EQA;
544 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
545 strcpy(buffer, "text");
546 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
547 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
548 EXPECT_EQA;
550 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
551 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
552 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
553 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
554 EXPECT_LENA; EXPECT_EQA;
556 STRINGSA("'''", "'"); /* invalid quoted string */
557 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
558 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
559 EXPECT_LENA; EXPECT_EQA;
561 /* test that msdn suggested single quotation usage works as expected */
562 STRINGSA("''''", "'"); /* single quote mark */
563 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
564 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
565 EXPECT_LENA; EXPECT_EQA;
567 STRINGSA("''HHHHHH", "08"); /* Normal use */
568 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
569 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
570 EXPECT_LENA; EXPECT_EQA;
572 /* and test for normal use of the single quotation mark */
573 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
574 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
575 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
576 EXPECT_LENA; EXPECT_EQA;
578 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
579 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
580 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
581 EXPECT_LENA; EXPECT_EQA;
583 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
584 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
585 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
586 EXPECT_LENA; EXPECT_EQA;
588 curtime.wHour = 25;
589 STRINGSA("'123'tt", ""); /* Invalid time */
590 SetLastError(0xdeadbeef);
591 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
592 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
593 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
595 curtime.wHour = 12;
596 curtime.wMonth = 60; /* Invalid */
597 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
598 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
599 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
600 EXPECT_LENA; EXPECT_EQA;
603 static void test_GetDateFormatA(void)
605 int ret;
606 SYSTEMTIME curtime;
607 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
608 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
609 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
610 char Broken[BUFFER_SIZE];
611 char short_day[10], month[10], genitive_month[10];
613 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
614 STRINGSA("ddd',' MMM dd yy","");
615 SetLastError(0xdeadbeef);
616 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
617 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
618 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
620 curtime.wYear = 2002;
621 curtime.wMonth = 5;
622 curtime.wDay = 4;
623 curtime.wDayOfWeek = 3;
624 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
625 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
626 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
627 EXPECT_LENA; EXPECT_EQA;
629 /* Same as above but with LOCALE_NOUSEROVERRIDE */
630 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
631 SetLastError(0xdeadbeef);
632 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
633 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
634 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
635 EXPECT_EQA;
637 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
638 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
639 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
640 EXPECT_LENA; EXPECT_EQA;
642 curtime.wHour = 36; /* Invalid */
643 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
644 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
645 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
646 EXPECT_LENA; EXPECT_EQA;
648 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
649 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
650 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
651 EXPECT_EQA;
653 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
654 SetLastError(0xdeadbeef);
655 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
656 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
657 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
659 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
660 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
661 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
662 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
663 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
665 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
666 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
667 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
668 EXPECT_LENA; EXPECT_EQA;
670 /* test for expected DATE_YEARMONTH behavior with null format */
671 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
672 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
673 SetLastError(0xdeadbeef);
674 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
675 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
676 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
677 EXPECT_EQA;
679 /* Test that using invalid DATE_* flags results in the correct error */
680 /* and return values */
681 STRINGSA("m/d/y", ""); /* Invalid flags */
682 SetLastError(0xdeadbeef);
683 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
684 &curtime, input, buffer, COUNTOF(buffer));
685 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
686 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
688 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
689 if (!ret)
691 win_skip("LANG_RUSSIAN locale data unavailable\n");
692 return;
695 /* month part should be in genitive form */
696 strcpy(genitive_month, buffer + 2);
697 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
698 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
699 strcpy(month, buffer);
700 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
702 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
703 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
704 strcpy(short_day, buffer);
706 STRINGSA("dd MMMMddd dd", "");
707 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
708 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
709 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
710 EXPECT_EQA;
712 STRINGSA("MMMMddd dd", "");
713 sprintf(Expected, "%s%s 04", month, short_day);
714 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
715 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
716 EXPECT_EQA;
718 STRINGSA("MMMMddd", "");
719 sprintf(Expected, "%s%s", month, short_day);
720 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
721 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
722 EXPECT_EQA;
724 STRINGSA("MMMMdd", "");
725 sprintf(Expected, "%s04", genitive_month);
726 sprintf(Broken, "%s04", month);
727 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
728 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
729 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
730 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
731 "Expected '%s', got '%s'\n", Expected, buffer);
733 STRINGSA("MMMMdd ddd", "");
734 sprintf(Expected, "%s04 %s", genitive_month, short_day);
735 sprintf(Broken, "%s04 %s", month, short_day);
736 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
737 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
738 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
739 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
740 "Expected '%s', got '%s'\n", Expected, buffer);
742 STRINGSA("dd dddMMMM", "");
743 sprintf(Expected, "04 %s%s", short_day, month);
744 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
745 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
746 EXPECT_EQA;
748 STRINGSA("dd dddMMMM ddd MMMMdd", "");
749 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
750 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
751 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
752 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
753 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
754 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
755 "Expected '%s', got '%s'\n", Expected, buffer);
757 /* with literal part */
758 STRINGSA("ddd',' MMMM dd", "");
759 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
760 sprintf(Broken, "%s, %s 04", short_day, month);
761 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
762 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
763 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
764 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
765 "Expected '%s', got '%s'\n", Expected, buffer);
768 static void test_GetDateFormatW(void)
770 int ret;
771 SYSTEMTIME curtime;
772 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
773 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
775 STRINGSW("",""); /* If flags is not zero then format must be NULL */
776 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
777 input, buffer, COUNTOF(buffer));
778 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
780 win_skip("GetDateFormatW is not implemented\n");
781 return;
783 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
784 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
785 EXPECT_EQW;
787 STRINGSW("",""); /* NULL buffer, len > 0 */
788 SetLastError(0xdeadbeef);
789 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
790 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
791 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
793 STRINGSW("",""); /* NULL buffer, len == 0 */
794 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
795 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
796 EXPECT_LENW; EXPECT_EQW;
798 curtime.wYear = 2002;
799 curtime.wMonth = 10;
800 curtime.wDay = 23;
801 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
802 curtime.wHour = 65432; /* Invalid */
803 curtime.wMinute = 34512; /* Invalid */
804 curtime.wSecond = 65535; /* Invalid */
805 curtime.wMilliseconds = 12345;
806 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
807 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
808 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
809 EXPECT_LENW; EXPECT_EQW;
811 /* Limit tests */
813 curtime.wYear = 1601;
814 curtime.wMonth = 1;
815 curtime.wDay = 1;
816 curtime.wDayOfWeek = 0; /* Irrelevant */
817 curtime.wHour = 0;
818 curtime.wMinute = 0;
819 curtime.wSecond = 0;
820 curtime.wMilliseconds = 0;
821 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
822 SetLastError(0xdeadbeef);
823 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
824 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
825 EXPECT_LENW; EXPECT_EQW;
827 curtime.wYear = 1600;
828 curtime.wMonth = 12;
829 curtime.wDay = 31;
830 curtime.wDayOfWeek = 0; /* Irrelevant */
831 curtime.wHour = 23;
832 curtime.wMinute = 59;
833 curtime.wSecond = 59;
834 curtime.wMilliseconds = 999;
835 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
836 SetLastError(0xdeadbeef);
837 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
838 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
839 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
843 #define CY_POS_LEFT 0
844 #define CY_POS_RIGHT 1
845 #define CY_POS_LEFT_SPACE 2
846 #define CY_POS_RIGHT_SPACE 3
848 static void test_GetCurrencyFormatA(void)
850 static char szDot[] = { '.', '\0' };
851 static char szComma[] = { ',', '\0' };
852 static char szDollar[] = { '$', '\0' };
853 int ret;
854 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
855 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
856 CURRENCYFMTA format;
858 memset(&format, 0, sizeof(format));
860 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
861 SetLastError(0xdeadbeef);
862 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
863 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
864 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
866 STRINGSA("23,53",""); /* Invalid character --> Error */
867 SetLastError(0xdeadbeef);
868 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
869 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
870 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
872 STRINGSA("--",""); /* Double '-' --> Error */
873 SetLastError(0xdeadbeef);
874 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
875 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
876 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
878 STRINGSA("0-",""); /* Trailing '-' --> Error */
879 SetLastError(0xdeadbeef);
880 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
881 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
882 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
884 STRINGSA("0..",""); /* Double '.' --> Error */
885 SetLastError(0xdeadbeef);
886 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
887 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
888 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
890 STRINGSA(" 0.1",""); /* Leading space --> Error */
891 SetLastError(0xdeadbeef);
892 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
893 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
894 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
896 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
897 SetLastError(0xdeadbeef);
898 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
899 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
900 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
902 STRINGSA("2353",""); /* Format and flags given --> Error */
903 SetLastError(0xdeadbeef);
904 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
905 ok( !ret, "Expected ret == 0, got %d\n", ret);
906 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
907 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
909 STRINGSA("2353",""); /* Invalid format --> Error */
910 SetLastError(0xdeadbeef);
911 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
912 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
913 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
915 STRINGSA("2353","$2,353.00"); /* Valid number */
916 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
917 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
918 EXPECT_LENA; EXPECT_EQA;
920 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
921 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
922 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
923 EXPECT_LENA; EXPECT_EQA;
925 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
926 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
927 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
928 EXPECT_LENA; EXPECT_EQA;
930 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
931 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
932 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
933 EXPECT_LENA; EXPECT_EQA;
935 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
936 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
937 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
938 EXPECT_LENA; EXPECT_EQA;
940 format.NumDigits = 0; /* No decimal separator */
941 format.LeadingZero = 0;
942 format.Grouping = 0; /* No grouping char */
943 format.NegativeOrder = 0;
944 format.PositiveOrder = CY_POS_LEFT;
945 format.lpDecimalSep = szDot;
946 format.lpThousandSep = szComma;
947 format.lpCurrencySymbol = szDollar;
949 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
950 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
951 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
952 EXPECT_LENA; EXPECT_EQA;
954 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
955 STRINGSA("2353","$2353.0");
956 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
957 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
958 EXPECT_LENA; EXPECT_EQA;
960 format.Grouping = 2; /* Group by 100's */
961 STRINGSA("2353","$23,53.0");
962 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
963 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
964 EXPECT_LENA; EXPECT_EQA;
966 STRINGSA("235","$235.0"); /* Grouping of a positive number */
967 format.Grouping = 3;
968 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
969 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
970 EXPECT_LENA; EXPECT_EQA;
972 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
973 format.NegativeOrder = 2;
974 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
975 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
976 EXPECT_LENA; EXPECT_EQA;
978 format.LeadingZero = 1; /* Always provide leading zero */
979 STRINGSA(".5","$0.5");
980 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
981 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
982 EXPECT_LENA; EXPECT_EQA;
984 format.PositiveOrder = CY_POS_RIGHT;
985 STRINGSA("1","1.0$");
986 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
987 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
988 EXPECT_LENA; EXPECT_EQA;
990 format.PositiveOrder = CY_POS_LEFT_SPACE;
991 STRINGSA("1","$ 1.0");
992 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
993 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
994 EXPECT_LENA; EXPECT_EQA;
996 format.PositiveOrder = CY_POS_RIGHT_SPACE;
997 STRINGSA("1","1.0 $");
998 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
999 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1000 EXPECT_LENA; EXPECT_EQA;
1002 format.NegativeOrder = 0;
1003 STRINGSA("-1","($1.0)");
1004 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1005 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1006 EXPECT_LENA; EXPECT_EQA;
1008 format.NegativeOrder = 1;
1009 STRINGSA("-1","-$1.0");
1010 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1011 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1012 EXPECT_LENA; EXPECT_EQA;
1014 format.NegativeOrder = 2;
1015 STRINGSA("-1","$-1.0");
1016 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1017 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1018 EXPECT_LENA; EXPECT_EQA;
1020 format.NegativeOrder = 3;
1021 STRINGSA("-1","$1.0-");
1022 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1023 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1024 EXPECT_LENA; EXPECT_EQA;
1026 format.NegativeOrder = 4;
1027 STRINGSA("-1","(1.0$)");
1028 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1029 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1030 EXPECT_LENA; EXPECT_EQA;
1032 format.NegativeOrder = 5;
1033 STRINGSA("-1","-1.0$");
1034 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1036 EXPECT_LENA; EXPECT_EQA;
1038 format.NegativeOrder = 6;
1039 STRINGSA("-1","1.0-$");
1040 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1041 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1042 EXPECT_LENA; EXPECT_EQA;
1044 format.NegativeOrder = 7;
1045 STRINGSA("-1","1.0$-");
1046 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1047 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1048 EXPECT_LENA; EXPECT_EQA;
1050 format.NegativeOrder = 8;
1051 STRINGSA("-1","-1.0 $");
1052 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1053 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1054 EXPECT_LENA; EXPECT_EQA;
1056 format.NegativeOrder = 9;
1057 STRINGSA("-1","-$ 1.0");
1058 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1059 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1060 EXPECT_LENA; EXPECT_EQA;
1062 format.NegativeOrder = 10;
1063 STRINGSA("-1","1.0 $-");
1064 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1065 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1066 EXPECT_LENA; EXPECT_EQA;
1068 format.NegativeOrder = 11;
1069 STRINGSA("-1","$ 1.0-");
1070 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1071 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1072 EXPECT_LENA; EXPECT_EQA;
1074 format.NegativeOrder = 12;
1075 STRINGSA("-1","$ -1.0");
1076 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1077 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1078 EXPECT_LENA; EXPECT_EQA;
1080 format.NegativeOrder = 13;
1081 STRINGSA("-1","1.0- $");
1082 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1083 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1084 EXPECT_LENA; EXPECT_EQA;
1086 format.NegativeOrder = 14;
1087 STRINGSA("-1","($ 1.0)");
1088 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1089 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1090 EXPECT_LENA; EXPECT_EQA;
1092 format.NegativeOrder = 15;
1093 STRINGSA("-1","(1.0 $)");
1094 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1095 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1096 EXPECT_LENA; EXPECT_EQA;
1099 #define NEG_PARENS 0 /* "(1.1)" */
1100 #define NEG_LEFT 1 /* "-1.1" */
1101 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1102 #define NEG_RIGHT 3 /* "1.1-" */
1103 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1105 static void test_GetNumberFormatA(void)
1107 static char szDot[] = { '.', '\0' };
1108 static char szComma[] = { ',', '\0' };
1109 int ret;
1110 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1111 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1112 NUMBERFMTA format;
1114 memset(&format, 0, sizeof(format));
1116 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1117 SetLastError(0xdeadbeef);
1118 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1119 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1120 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1122 STRINGSA("23,53",""); /* Invalid character --> Error */
1123 SetLastError(0xdeadbeef);
1124 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1125 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1126 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1128 STRINGSA("--",""); /* Double '-' --> Error */
1129 SetLastError(0xdeadbeef);
1130 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1131 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1132 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1134 STRINGSA("0-",""); /* Trailing '-' --> Error */
1135 SetLastError(0xdeadbeef);
1136 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1137 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1138 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1140 STRINGSA("0..",""); /* Double '.' --> Error */
1141 SetLastError(0xdeadbeef);
1142 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1143 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1144 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1146 STRINGSA(" 0.1",""); /* Leading space --> Error */
1147 SetLastError(0xdeadbeef);
1148 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1149 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1150 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1152 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1153 SetLastError(0xdeadbeef);
1154 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1155 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1156 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1158 STRINGSA("2353",""); /* Format and flags given --> Error */
1159 SetLastError(0xdeadbeef);
1160 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1161 ok( !ret, "Expected ret == 0, got %d\n", ret);
1162 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1163 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1165 STRINGSA("2353",""); /* Invalid format --> Error */
1166 SetLastError(0xdeadbeef);
1167 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1168 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1169 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1171 STRINGSA("2353","2,353.00"); /* Valid number */
1172 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1173 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1174 EXPECT_LENA; EXPECT_EQA;
1176 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1177 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1178 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1179 EXPECT_LENA; EXPECT_EQA;
1181 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1182 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1183 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1184 EXPECT_LENA; EXPECT_EQA;
1186 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1187 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1188 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1189 EXPECT_LENA; EXPECT_EQA;
1191 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1192 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1193 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1194 EXPECT_LENA; EXPECT_EQA;
1196 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1197 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1198 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1199 EXPECT_LENA; EXPECT_EQA;
1201 format.NumDigits = 0; /* No decimal separator */
1202 format.LeadingZero = 0;
1203 format.Grouping = 0; /* No grouping char */
1204 format.NegativeOrder = 0;
1205 format.lpDecimalSep = szDot;
1206 format.lpThousandSep = szComma;
1208 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1209 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1210 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1211 EXPECT_LENA; EXPECT_EQA;
1213 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1214 STRINGSA("2353","2353.0");
1215 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1216 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1217 EXPECT_LENA; EXPECT_EQA;
1219 format.Grouping = 2; /* Group by 100's */
1220 STRINGSA("2353","23,53.0");
1221 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1222 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1223 EXPECT_LENA; EXPECT_EQA;
1225 STRINGSA("235","235.0"); /* Grouping of a positive number */
1226 format.Grouping = 3;
1227 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1228 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1229 EXPECT_LENA; EXPECT_EQA;
1231 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1232 format.NegativeOrder = NEG_LEFT;
1233 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1234 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1235 EXPECT_LENA; EXPECT_EQA;
1237 format.LeadingZero = 1; /* Always provide leading zero */
1238 STRINGSA(".5","0.5");
1239 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1240 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1241 EXPECT_LENA; EXPECT_EQA;
1243 format.NegativeOrder = NEG_PARENS;
1244 STRINGSA("-1","(1.0)");
1245 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1246 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1247 EXPECT_LENA; EXPECT_EQA;
1249 format.NegativeOrder = NEG_LEFT;
1250 STRINGSA("-1","-1.0");
1251 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1252 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1253 EXPECT_LENA; EXPECT_EQA;
1255 format.NegativeOrder = NEG_LEFT_SPACE;
1256 STRINGSA("-1","- 1.0");
1257 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1258 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1259 EXPECT_LENA; EXPECT_EQA;
1261 format.NegativeOrder = NEG_RIGHT;
1262 STRINGSA("-1","1.0-");
1263 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1264 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1265 EXPECT_LENA; EXPECT_EQA;
1267 format.NegativeOrder = NEG_RIGHT_SPACE;
1268 STRINGSA("-1","1.0 -");
1269 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1270 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1271 EXPECT_LENA; EXPECT_EQA;
1273 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1275 if (IsValidLocale(lcid, 0))
1277 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1278 Expected[3] = 160; /* Non breaking space */
1279 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1280 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1281 EXPECT_LENA; EXPECT_EQA;
1285 struct comparestringa_entry {
1286 LCID lcid;
1287 DWORD flags;
1288 const char *first;
1289 int first_len;
1290 const char *second;
1291 int second_len;
1292 int ret;
1295 static const struct comparestringa_entry comparestringa_data[] = {
1296 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1297 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1298 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1299 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1300 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1301 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1302 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1303 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1304 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1305 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1306 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1307 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1308 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1309 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1310 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1311 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1312 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1313 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1314 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1315 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1316 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1317 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1318 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1319 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1320 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1321 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1322 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1323 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1324 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1325 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1328 static void test_CompareStringA(void)
1330 int ret, i;
1331 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1333 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1335 const struct comparestringa_entry *entry = &comparestringa_data[i];
1337 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1338 entry->second, entry->second_len);
1339 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1342 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1343 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1345 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1346 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1348 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1349 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1351 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1352 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1354 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1356 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1357 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1359 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1360 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1362 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1363 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1365 /* test for CompareStringA flags */
1366 SetLastError(0xdeadbeef);
1367 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1368 ok(GetLastError() == ERROR_INVALID_FLAGS,
1369 "unexpected error code %d\n", GetLastError());
1370 ok(!ret, "CompareStringA must fail with invalid flag\n");
1372 SetLastError(0xdeadbeef);
1373 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1374 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1375 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1376 /* end of test for CompareStringA flags */
1378 ret = lstrcmpA("", "");
1379 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1381 ret = lstrcmpA(NULL, NULL);
1382 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1384 ret = lstrcmpA("", NULL);
1385 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1387 ret = lstrcmpA(NULL, "");
1388 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1391 if (0) { /* this requires collation table patch to make it MS compatible */
1392 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1393 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1395 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1396 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1398 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1399 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1401 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1402 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1404 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1405 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1407 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1408 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1410 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1411 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1413 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1414 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1416 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1417 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1419 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1420 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1422 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1423 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1425 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1426 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1430 /* WinXP handles embedded NULLs differently than earlier versions */
1431 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1432 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1434 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1435 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);
1437 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1438 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1440 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1441 ok(ret == CSTR_EQUAL || /* win2k */
1442 ret == CSTR_GREATER_THAN,
1443 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1445 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1446 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1448 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1449 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1451 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1452 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1454 ret = lstrcmpi("#", ".");
1455 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1457 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1459 /* \xB9 character lies between a and b */
1460 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1461 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1462 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1463 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1466 static void test_LCMapStringA(void)
1468 int ret, ret2;
1469 char buf[256], buf2[256];
1470 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1471 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1472 static const char symbols_stripped[] = "justateststring1";
1474 SetLastError(0xdeadbeef);
1475 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1476 lower_case, -1, buf, sizeof(buf));
1477 ok(ret == lstrlenA(lower_case) + 1,
1478 "ret %d, error %d, expected value %d\n",
1479 ret, GetLastError(), lstrlenA(lower_case) + 1);
1480 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1482 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1483 upper_case, -1, buf, sizeof(buf));
1484 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1485 ok(GetLastError() == ERROR_INVALID_FLAGS,
1486 "unexpected error code %d\n", GetLastError());
1488 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1489 upper_case, -1, buf, sizeof(buf));
1490 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1491 ok(GetLastError() == ERROR_INVALID_FLAGS,
1492 "unexpected error code %d\n", GetLastError());
1494 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1495 upper_case, -1, buf, sizeof(buf));
1496 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1497 ok(GetLastError() == ERROR_INVALID_FLAGS,
1498 "unexpected error code %d\n", GetLastError());
1500 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1501 upper_case, -1, buf, sizeof(buf));
1502 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1503 ok(GetLastError() == ERROR_INVALID_FLAGS,
1504 "unexpected error code %d\n", GetLastError());
1506 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1507 SetLastError(0xdeadbeef);
1508 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1509 upper_case, -1, buf, sizeof(buf));
1510 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1511 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1513 /* test LCMAP_LOWERCASE */
1514 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1515 upper_case, -1, buf, sizeof(buf));
1516 ok(ret == lstrlenA(upper_case) + 1,
1517 "ret %d, error %d, expected value %d\n",
1518 ret, GetLastError(), lstrlenA(upper_case) + 1);
1519 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1521 /* test LCMAP_UPPERCASE */
1522 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1523 lower_case, -1, buf, sizeof(buf));
1524 ok(ret == lstrlenA(lower_case) + 1,
1525 "ret %d, error %d, expected value %d\n",
1526 ret, GetLastError(), lstrlenA(lower_case) + 1);
1527 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1529 /* test buffer overflow */
1530 SetLastError(0xdeadbeef);
1531 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1532 lower_case, -1, buf, 4);
1533 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1534 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1536 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1537 lstrcpyA(buf, lower_case);
1538 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1539 buf, -1, buf, sizeof(buf));
1540 if (!ret) /* Win9x */
1541 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1542 else
1544 ok(ret == lstrlenA(lower_case) + 1,
1545 "ret %d, error %d, expected value %d\n",
1546 ret, GetLastError(), lstrlenA(lower_case) + 1);
1547 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1549 lstrcpyA(buf, upper_case);
1550 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1551 buf, -1, buf, sizeof(buf));
1552 if (!ret) /* Win9x */
1553 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1554 else
1556 ok(ret == lstrlenA(upper_case) + 1,
1557 "ret %d, error %d, expected value %d\n",
1558 ret, GetLastError(), lstrlenA(lower_case) + 1);
1559 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1562 /* otherwise src == dst should fail */
1563 SetLastError(0xdeadbeef);
1564 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1565 buf, 10, buf, sizeof(buf));
1566 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1567 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1568 "unexpected error code %d\n", GetLastError());
1569 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1571 /* test whether '\0' is always appended */
1572 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1573 upper_case, -1, buf, sizeof(buf));
1574 ok(ret, "LCMapStringA must succeed\n");
1575 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1576 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1577 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1578 ok(ret2, "LCMapStringA must succeed\n");
1579 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1580 ok(ret == ret2, "lengths of sort keys must be equal\n");
1581 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1583 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1584 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1585 upper_case, -1, buf, sizeof(buf));
1586 ok(ret, "LCMapStringA must succeed\n");
1587 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1588 lower_case, -1, buf2, sizeof(buf2));
1589 ok(ret2, "LCMapStringA must succeed\n");
1590 ok(ret == ret2, "lengths of sort keys must be equal\n");
1591 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1593 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1594 results from plain LCMAP_SORTKEY on Vista */
1596 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1597 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1598 lower_case, -1, buf, sizeof(buf));
1599 ok(ret, "LCMapStringA must succeed\n");
1600 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1601 symbols_stripped, -1, buf2, sizeof(buf2));
1602 ok(ret2, "LCMapStringA must succeed\n");
1603 ok(ret == ret2, "lengths of sort keys must be equal\n");
1604 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1606 /* test NORM_IGNORENONSPACE */
1607 lstrcpyA(buf, "foo");
1608 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1609 lower_case, -1, buf, sizeof(buf));
1610 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1611 lstrlenA(lower_case) + 1, ret);
1612 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1614 /* test NORM_IGNORESYMBOLS */
1615 lstrcpyA(buf, "foo");
1616 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1617 lower_case, -1, buf, sizeof(buf));
1618 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1619 lstrlenA(symbols_stripped) + 1, ret);
1620 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1622 /* test srclen = 0 */
1623 SetLastError(0xdeadbeef);
1624 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1625 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1626 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1627 "unexpected error code %d\n", GetLastError());
1630 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1632 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1634 int ret, ret2;
1635 WCHAR buf[256], buf2[256];
1636 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1638 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1639 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1640 if (broken(ret))
1641 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1642 else
1644 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1645 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1646 func_name, GetLastError());
1649 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1650 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1651 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1652 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1653 func_name, GetLastError());
1655 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1656 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1657 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1658 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1659 func_name, GetLastError());
1661 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1662 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1663 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1664 func_name);
1665 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1666 func_name, GetLastError());
1668 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1669 SetLastError(0xdeadbeef);
1670 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1671 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1672 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1673 func_name, GetLastError());
1674 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1676 /* test LCMAP_LOWERCASE */
1677 ret = func_ptr(LCMAP_LOWERCASE,
1678 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1679 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1680 ret, GetLastError(), lstrlenW(upper_case) + 1);
1681 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1683 /* test LCMAP_UPPERCASE */
1684 ret = func_ptr(LCMAP_UPPERCASE,
1685 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1686 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1687 ret, GetLastError(), lstrlenW(lower_case) + 1);
1688 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1690 /* test buffer overflow */
1691 SetLastError(0xdeadbeef);
1692 ret = func_ptr(LCMAP_UPPERCASE,
1693 lower_case, -1, buf, 4);
1694 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1695 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1697 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1698 lstrcpyW(buf, lower_case);
1699 ret = func_ptr(LCMAP_UPPERCASE,
1700 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1701 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1702 ret, GetLastError(), lstrlenW(lower_case) + 1);
1703 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1705 lstrcpyW(buf, upper_case);
1706 ret = func_ptr(LCMAP_LOWERCASE,
1707 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1708 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1709 ret, GetLastError(), lstrlenW(lower_case) + 1);
1710 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1712 /* otherwise src == dst should fail */
1713 SetLastError(0xdeadbeef);
1714 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1715 buf, 10, buf, sizeof(buf));
1716 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1717 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1718 "%s unexpected error code %d\n", func_name, GetLastError());
1719 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1721 /* test whether '\0' is always appended */
1722 ret = func_ptr(LCMAP_SORTKEY,
1723 upper_case, -1, buf, sizeof(buf));
1724 ok(ret, "%s func_ptr must succeed\n", func_name);
1725 ret2 = func_ptr(LCMAP_SORTKEY,
1726 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1727 ok(ret, "%s func_ptr must succeed\n", func_name);
1728 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1729 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1731 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1732 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1733 upper_case, -1, buf, sizeof(buf));
1734 ok(ret, "%s func_ptr must succeed\n", func_name);
1735 ret2 = func_ptr(LCMAP_SORTKEY,
1736 lower_case, -1, buf2, sizeof(buf2));
1737 ok(ret2, "%s func_ptr must succeed\n", func_name);
1738 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1739 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1741 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1742 results from plain LCMAP_SORTKEY on Vista */
1744 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1745 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1746 lower_case, -1, buf, sizeof(buf));
1747 ok(ret, "%s func_ptr must succeed\n", func_name);
1748 ret2 = func_ptr(LCMAP_SORTKEY,
1749 symbols_stripped, -1, buf2, sizeof(buf2));
1750 ok(ret2, "%s func_ptr must succeed\n", func_name);
1751 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1752 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1754 /* test NORM_IGNORENONSPACE */
1755 lstrcpyW(buf, fooW);
1756 ret = func_ptr(NORM_IGNORENONSPACE,
1757 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1758 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1759 lstrlenW(lower_case) + 1, ret);
1760 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1762 /* test NORM_IGNORESYMBOLS */
1763 lstrcpyW(buf, fooW);
1764 ret = func_ptr(NORM_IGNORESYMBOLS,
1765 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1766 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1767 lstrlenW(symbols_stripped) + 1, ret);
1768 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1770 /* test srclen = 0 */
1771 SetLastError(0xdeadbeef);
1772 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1773 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1774 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1775 "%s unexpected error code %d\n", func_name, GetLastError());
1778 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1780 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1783 static void test_LCMapStringW(void)
1785 int ret;
1786 WCHAR buf[256];
1788 trace("testing LCMapStringW\n");
1790 SetLastError(0xdeadbeef);
1791 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1792 todo_wine {
1793 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1794 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1797 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1800 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1802 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1805 static void test_LCMapStringEx(void)
1807 int ret;
1808 WCHAR buf[256];
1810 if (!pLCMapStringEx)
1812 win_skip( "LCMapStringEx not available\n" );
1813 return;
1816 trace("testing LCMapStringEx\n");
1818 SetLastError(0xdeadbeef);
1819 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
1820 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1821 todo_wine {
1822 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1823 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1826 /* test reserved parameters */
1827 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1828 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1829 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1830 ret, GetLastError(), lstrlenW(upper_case) + 1);
1831 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1833 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1834 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1835 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1836 ret, GetLastError(), lstrlenW(upper_case) + 1);
1837 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1839 /* crashes on native */
1840 if(0)
1841 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1842 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1844 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1847 struct neutralsublang_name_t {
1848 WCHAR name[3];
1849 LCID lcid;
1850 int todo;
1853 static const struct neutralsublang_name_t neutralsublang_names[] = {
1854 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1855 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1856 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1857 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1858 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1859 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1860 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1861 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1862 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1863 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1864 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1865 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1866 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1867 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1868 { {0} }
1871 static void test_LocaleNameToLCID(void)
1873 LCID lcid;
1874 INT ret;
1875 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1876 static const WCHAR enW[] = {'e','n',0};
1878 if (!pLocaleNameToLCID)
1880 win_skip( "LocaleNameToLCID not available\n" );
1881 return;
1884 /* special cases */
1885 buffer[0] = 0;
1886 SetLastError(0xdeadbeef);
1887 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1888 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1889 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
1890 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1891 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1892 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1894 buffer[0] = 0;
1895 SetLastError(0xdeadbeef);
1896 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1897 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1898 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
1899 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1900 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1901 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1903 buffer[0] = 0;
1904 SetLastError(0xdeadbeef);
1905 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1906 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1907 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1908 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1909 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1911 /* bad name */
1912 SetLastError(0xdeadbeef);
1913 lcid = pLocaleNameToLCID(fooW, 0);
1914 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1915 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
1917 /* english neutral name */
1918 lcid = pLocaleNameToLCID(enW, 0);
1919 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1920 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1921 if (lcid)
1923 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1925 while (*ptr->name)
1927 lcid = pLocaleNameToLCID(ptr->name, 0);
1928 if (ptr->todo)
1929 todo_wine
1930 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1931 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1932 else
1933 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1934 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1936 *buffer = 0;
1937 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
1938 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
1939 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
1940 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
1942 ptr++;
1947 /* this requires collation table patch to make it MS compatible */
1948 static const char * const strings_sorted[] =
1950 "'",
1951 "-",
1952 "!",
1953 "\"",
1954 ".",
1955 ":",
1956 "\\",
1957 "_",
1958 "`",
1959 "{",
1960 "}",
1961 "+",
1962 "0",
1963 "1",
1964 "2",
1965 "3",
1966 "4",
1967 "5",
1968 "6",
1969 "7",
1970 "8",
1971 "9",
1972 "a",
1973 "A",
1974 "b",
1975 "B",
1976 "c",
1980 static const char * const strings[] =
1982 "C",
1983 "\"",
1984 "9",
1985 "'",
1986 "}",
1987 "-",
1988 "7",
1989 "+",
1990 "`",
1991 "1",
1992 "a",
1993 "5",
1994 "\\",
1995 "8",
1996 "B",
1997 "3",
1998 "_",
1999 "6",
2000 "{",
2001 "2",
2002 "c",
2003 "4",
2004 "!",
2005 "0",
2006 "A",
2007 ":",
2008 "b",
2012 static int compare_string1(const void *e1, const void *e2)
2014 const char *s1 = *(const char *const *)e1;
2015 const char *s2 = *(const char *const *)e2;
2017 return lstrcmpA(s1, s2);
2020 static int compare_string2(const void *e1, const void *e2)
2022 const char *s1 = *(const char *const *)e1;
2023 const char *s2 = *(const char *const *)e2;
2025 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2028 static int compare_string3(const void *e1, const void *e2)
2030 const char *s1 = *(const char *const *)e1;
2031 const char *s2 = *(const char *const *)e2;
2032 char key1[256], key2[256];
2034 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2035 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2036 return strcmp(key1, key2);
2039 static void test_sorting(void)
2041 char buf[256];
2042 char **str_buf = (char **)buf;
2043 int i;
2045 assert(sizeof(buf) >= sizeof(strings));
2047 /* 1. sort using lstrcmpA */
2048 memcpy(buf, strings, sizeof(strings));
2049 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2050 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2052 ok(!strcmp(strings_sorted[i], str_buf[i]),
2053 "qsort using lstrcmpA failed for element %d\n", i);
2055 /* 2. sort using CompareStringA */
2056 memcpy(buf, strings, sizeof(strings));
2057 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2058 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2060 ok(!strcmp(strings_sorted[i], str_buf[i]),
2061 "qsort using CompareStringA failed for element %d\n", i);
2063 /* 3. sort using sort keys */
2064 memcpy(buf, strings, sizeof(strings));
2065 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2066 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2068 ok(!strcmp(strings_sorted[i], str_buf[i]),
2069 "qsort using sort keys failed for element %d\n", i);
2073 static void test_FoldStringA(void)
2075 int ret, i, j;
2076 BOOL is_special;
2077 char src[256], dst[256];
2078 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2079 static const char digits_dst[] = { '1','2','3','\0' };
2080 static const char composite_src[] =
2082 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2083 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2084 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2085 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2086 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2087 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2088 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2089 0xfb,0xfc,0xfd,0xff,'\0'
2091 static const char composite_dst[] =
2093 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2094 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2095 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2096 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2097 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2098 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2099 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2100 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2101 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2102 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2103 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2104 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2105 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2106 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2107 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2109 static const char composite_dst_alt[] =
2111 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2112 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2113 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2114 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2115 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2116 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2117 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2118 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2119 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2120 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2121 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2122 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2123 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2124 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2125 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2127 static const char ligatures_src[] =
2129 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2131 static const char ligatures_dst[] =
2133 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2135 static const struct special
2137 char src;
2138 char dst[4];
2139 } foldczone_special[] =
2141 /* src dst */
2142 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2143 { 0x98, { 0x20, 0x7e, 0x00 } },
2144 { 0x99, { 0x54, 0x4d, 0x00 } },
2145 { 0xa0, { 0x20, 0x00 } },
2146 { 0xa8, { 0x20, 0xa8, 0x00 } },
2147 { 0xaa, { 0x61, 0x00 } },
2148 { 0xaf, { 0x20, 0xaf, 0x00 } },
2149 { 0xb2, { 0x32, 0x00 } },
2150 { 0xb3, { 0x33, 0x00 } },
2151 { 0xb4, { 0x20, 0xb4, 0x00 } },
2152 { 0xb8, { 0x20, 0xb8, 0x00 } },
2153 { 0xb9, { 0x31, 0x00 } },
2154 { 0xba, { 0x6f, 0x00 } },
2155 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2156 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2157 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2158 { 0x00 }
2161 if (!pFoldStringA)
2162 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2164 /* these tests are locale specific */
2165 if (GetACP() != 1252)
2167 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2168 return;
2171 /* MAP_FOLDDIGITS */
2172 SetLastError(0);
2173 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2174 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2176 win_skip("FoldStringA is not implemented\n");
2177 return;
2179 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2180 ok(strcmp(dst, digits_dst) == 0,
2181 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2182 for (i = 1; i < 256; i++)
2184 if (!strchr(digits_src, i))
2186 src[0] = i;
2187 src[1] = '\0';
2188 SetLastError(0);
2189 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2190 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2191 ok(dst[0] == src[0],
2192 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2196 /* MAP_EXPAND_LIGATURES */
2197 SetLastError(0);
2198 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2199 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2200 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2201 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2202 ok(strcmp(dst, ligatures_dst) == 0,
2203 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2204 for (i = 1; i < 256; i++)
2206 if (!strchr(ligatures_src, i))
2208 src[0] = i;
2209 src[1] = '\0';
2210 SetLastError(0);
2211 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2212 if (ret == 3)
2214 /* Vista */
2215 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2216 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2217 "Got %s for %d\n", dst, i);
2219 else
2221 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2222 ok(dst[0] == src[0],
2223 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2229 /* MAP_COMPOSITE */
2230 SetLastError(0);
2231 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2232 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2233 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2234 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2235 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2237 for (i = 1; i < 256; i++)
2239 if (!strchr(composite_src, i))
2241 src[0] = i;
2242 src[1] = '\0';
2243 SetLastError(0);
2244 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2245 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2246 ok(dst[0] == src[0],
2247 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2248 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2252 /* MAP_FOLDCZONE */
2253 for (i = 1; i < 256; i++)
2255 src[0] = i;
2256 src[1] = '\0';
2257 SetLastError(0);
2258 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2259 is_special = FALSE;
2260 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2262 if (foldczone_special[j].src == src[0])
2264 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2265 "Expected ret == 2 or %d, got %d, error %d\n",
2266 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2267 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2268 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2269 (unsigned char)src[0]);
2270 is_special = TRUE;
2273 if (! is_special)
2275 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2276 ok(src[0] == dst[0],
2277 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2278 (unsigned char)src[0], (unsigned char)dst[0]);
2282 /* MAP_PRECOMPOSED */
2283 for (i = 1; i < 256; i++)
2285 src[0] = i;
2286 src[1] = '\0';
2287 SetLastError(0);
2288 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2289 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2290 ok(src[0] == dst[0],
2291 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2292 (unsigned char)src[0], (unsigned char)dst[0]);
2296 static void test_FoldStringW(void)
2298 int ret;
2299 unsigned int i, j;
2300 WCHAR src[256], dst[256], ch, prev_ch = 1;
2301 static const DWORD badFlags[] =
2304 MAP_PRECOMPOSED|MAP_COMPOSITE,
2305 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2306 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2308 /* Ranges of digits 0-9 : Must be sorted! */
2309 static const WCHAR digitRanges[] =
2311 0x0030, /* '0'-'9' */
2312 0x0660, /* Eastern Arabic */
2313 0x06F0, /* Arabic - Hindu */
2314 0x0966, /* Devengari */
2315 0x09E6, /* Bengalii */
2316 0x0A66, /* Gurmukhi */
2317 0x0AE6, /* Gujarati */
2318 0x0B66, /* Oriya */
2319 0x0BE6, /* Tamil - No 0 */
2320 0x0C66, /* Telugu */
2321 0x0CE6, /* Kannada */
2322 0x0D66, /* Maylayalam */
2323 0x0E50, /* Thai */
2324 0x0ED0, /* Laos */
2325 0x0F29, /* Tibet - 0 is out of sequence */
2326 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2327 0x2080, /* Subscript */
2328 0x245F, /* Circled - 0 is out of sequence */
2329 0x2473, /* Bracketed */
2330 0x2487, /* Full stop */
2331 0x2775, /* Inverted circled - No 0 */
2332 0x277F, /* Patterned circled - No 0 */
2333 0x2789, /* Inverted Patterned circled - No 0 */
2334 0x3020, /* Hangzhou */
2335 0xff10, /* Pliene chasse (?) */
2336 0xffff /* Terminator */
2338 /* Digits which are represented, but out of sequence */
2339 static const WCHAR outOfSequenceDigits[] =
2341 0xB9, /* Superscript 1 */
2342 0xB2, /* Superscript 2 */
2343 0xB3, /* Superscript 3 */
2344 0x0F33, /* Tibetan half zero */
2345 0x24EA, /* Circled 0 */
2346 0x3007, /* Ideographic number zero */
2347 '\0' /* Terminator */
2349 /* Digits in digitRanges for which no representation is available */
2350 static const WCHAR noDigitAvailable[] =
2352 0x0BE6, /* No Tamil 0 */
2353 0x0F29, /* No Tibetan half zero (out of sequence) */
2354 0x2473, /* No Bracketed 0 */
2355 0x2487, /* No 0 Full stop */
2356 0x2775, /* No inverted circled 0 */
2357 0x277F, /* No patterned circled */
2358 0x2789, /* No inverted Patterned circled */
2359 0x3020, /* No Hangzhou 0 */
2360 '\0' /* Terminator */
2362 static const WCHAR foldczone_src[] =
2364 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2365 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2367 static const WCHAR foldczone_dst[] =
2369 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2371 static const WCHAR foldczone_todo_src[] =
2373 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2375 static const WCHAR foldczone_todo_dst[] =
2377 0x3cb,0x1f0,' ','a',0
2379 static const WCHAR foldczone_todo_broken_dst[] =
2381 0x3cb,0x1f0,0xa0,0xaa,0
2383 static const WCHAR ligatures_src[] =
2385 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2386 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2387 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2388 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2389 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2390 0xfb04, 0xfb05, 0xfb06, '\0'
2392 static const WCHAR ligatures_dst[] =
2394 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2395 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2396 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2397 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2398 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2399 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2402 if (!pFoldStringW)
2404 win_skip("FoldStringW is not available\n");
2405 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2408 /* Invalid flag combinations */
2409 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2411 src[0] = dst[0] = '\0';
2412 SetLastError(0);
2413 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2414 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2416 win_skip("FoldStringW is not implemented\n");
2417 return;
2419 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2420 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2423 /* src & dst cannot be the same */
2424 SetLastError(0);
2425 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2426 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2427 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2429 /* src can't be NULL */
2430 SetLastError(0);
2431 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2432 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2433 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2435 /* srclen can't be 0 */
2436 SetLastError(0);
2437 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2438 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2439 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2441 /* dstlen can't be < 0 */
2442 SetLastError(0);
2443 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2444 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2445 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2447 /* Ret includes terminating NUL which is appended if srclen = -1 */
2448 SetLastError(0);
2449 src[0] = 'A';
2450 src[1] = '\0';
2451 dst[0] = '\0';
2452 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2453 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2454 ok(dst[0] == 'A' && dst[1] == '\0',
2455 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2456 'A', '\0', ret, dst[0], dst[1], GetLastError());
2458 /* If size is given, result is not NUL terminated */
2459 SetLastError(0);
2460 src[0] = 'A';
2461 src[1] = 'A';
2462 dst[0] = 'X';
2463 dst[1] = 'X';
2464 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2465 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2466 ok(dst[0] == 'A' && dst[1] == 'X',
2467 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2468 'A','X', ret, dst[0], dst[1], GetLastError());
2470 /* MAP_FOLDDIGITS */
2471 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2473 /* Check everything before this range */
2474 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2476 SetLastError(0);
2477 src[0] = ch;
2478 src[1] = dst[0] = '\0';
2479 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2480 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2482 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2483 /* Wine (correctly) maps all Unicode 4.0+ digits */
2484 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2485 (ch >= 0x1369 && ch <= 0x1371),
2486 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2489 if (digitRanges[j] == 0xffff)
2490 break; /* Finished the whole code point space */
2492 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2494 WCHAR c;
2496 /* Map out of sequence characters */
2497 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2498 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2499 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2500 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2501 else c = ch;
2502 SetLastError(0);
2503 src[0] = c;
2504 src[1] = dst[0] = '\0';
2505 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2506 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2508 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2509 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2510 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2511 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2512 strchrW(noDigitAvailable, c),
2513 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2514 ch, '0' + digitRanges[j] - ch, dst[0]);
2516 prev_ch = ch;
2519 /* MAP_FOLDCZONE */
2520 SetLastError(0);
2521 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2522 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2523 "Got %d, error %d\n", ret, GetLastError());
2524 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2525 "MAP_FOLDCZONE: Expanded incorrectly\n");
2527 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2528 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2529 "Got %d, error %d\n", ret, GetLastError());
2530 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2531 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2532 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2534 /* MAP_EXPAND_LIGATURES */
2535 SetLastError(0);
2536 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2537 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2538 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2539 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2540 "Got %d, error %d\n", ret, GetLastError());
2541 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2542 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2545 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2550 #define LCID_OK(l) \
2551 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2552 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2553 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2554 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2555 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2557 static void test_ConvertDefaultLocale(void)
2559 LCID lcid;
2561 /* Doesn't change lcid, even if non default sublang/sort used */
2562 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2563 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2564 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2565 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2567 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2568 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2569 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2570 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2571 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2573 /* Invariant language is not treated specially */
2574 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2576 /* User/system default languages alone are not mapped */
2577 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2578 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2580 /* Default lcids */
2581 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2582 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2583 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2586 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2587 DWORD dwFlags, LONG_PTR lParam)
2589 trace("%08x, %s, %s, %08x, %08lx\n",
2590 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2592 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2593 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2595 /* If lParam is one, we are calling with flags defaulted from 0 */
2596 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2597 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2599 return TRUE;
2602 static void test_EnumSystemLanguageGroupsA(void)
2604 BOOL ret;
2606 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2608 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2609 return;
2612 /* No enumeration proc */
2613 SetLastError(0);
2614 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2615 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2617 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2618 return;
2620 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2621 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2623 /* Invalid flags */
2624 SetLastError(0);
2625 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2626 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2628 /* No flags - defaults to LGRPID_INSTALLED */
2629 SetLastError(0xdeadbeef);
2630 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2631 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2633 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2634 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2637 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2639 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2640 return TRUE;
2643 static void test_EnumSystemLocalesEx(void)
2645 BOOL ret;
2647 if (!pEnumSystemLocalesEx)
2649 win_skip( "EnumSystemLocalesEx not available\n" );
2650 return;
2652 SetLastError( 0xdeadbeef );
2653 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2654 ok( !ret, "should have failed\n" );
2655 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2656 SetLastError( 0xdeadbeef );
2657 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2658 ok( ret, "failed err %u\n", GetLastError() );
2661 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2662 LONG_PTR lParam)
2664 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2666 /* invalid locale enumerated on some platforms */
2667 if (lcid == 0)
2668 return TRUE;
2670 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2671 "Enumerated grp %d not valid\n", lgrpid);
2672 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2673 "Enumerated grp locale %d not valid\n", lcid);
2674 return TRUE;
2677 static void test_EnumLanguageGroupLocalesA(void)
2679 BOOL ret;
2681 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2683 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2684 return;
2687 /* No enumeration proc */
2688 SetLastError(0);
2689 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2690 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2692 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2693 return;
2695 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2696 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2698 /* lgrpid too small */
2699 SetLastError(0);
2700 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2701 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2702 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2704 /* lgrpid too big */
2705 SetLastError(0);
2706 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2707 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2708 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2710 /* dwFlags is reserved */
2711 SetLastError(0);
2712 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2713 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2714 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2716 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2719 static void test_SetLocaleInfoA(void)
2721 BOOL bRet;
2722 LCID lcid = GetUserDefaultLCID();
2724 /* Null data */
2725 SetLastError(0);
2726 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2727 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2728 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2730 /* IDATE */
2731 SetLastError(0);
2732 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2733 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2734 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2736 /* ILDATE */
2737 SetLastError(0);
2738 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2739 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2740 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2743 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2745 trace("%s %08lx\n", value, lParam);
2746 return(TRUE);
2749 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2751 ok(!enumCount, "callback called again unexpected\n");
2752 enumCount++;
2753 return(FALSE);
2756 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2758 ok(0,"callback called unexpected\n");
2759 return(FALSE);
2762 static void test_EnumUILanguageA(void)
2764 BOOL ret;
2765 if (!pEnumUILanguagesA) {
2766 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2767 return;
2770 SetLastError(ERROR_SUCCESS);
2771 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2772 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2774 win_skip("EnumUILanguagesA is not implemented\n");
2775 return;
2777 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2779 enumCount = 0;
2780 SetLastError(ERROR_SUCCESS);
2781 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2782 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2784 SetLastError(ERROR_SUCCESS);
2785 ret = pEnumUILanguagesA(NULL, 0, 0);
2786 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2787 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2788 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2790 SetLastError(ERROR_SUCCESS);
2791 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2792 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2793 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2795 SetLastError(ERROR_SUCCESS);
2796 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2797 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2798 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2799 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2802 static char date_fmt_buf[1024];
2804 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2806 lstrcatA(date_fmt_buf, fmt);
2807 lstrcatA(date_fmt_buf, "\n");
2808 return TRUE;
2811 static void test_EnumDateFormatsA(void)
2813 char *p, buf[256];
2814 BOOL ret;
2815 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2817 trace("EnumDateFormatsA 0\n");
2818 date_fmt_buf[0] = 0;
2819 SetLastError(0xdeadbeef);
2820 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2821 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2823 win_skip("0 for dwFlags is not supported\n");
2825 else
2827 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2828 trace("%s\n", date_fmt_buf);
2829 /* test the 1st enumerated format */
2830 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2831 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2832 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2833 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2836 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2837 date_fmt_buf[0] = 0;
2838 SetLastError(0xdeadbeef);
2839 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2840 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2842 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2844 else
2846 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2847 trace("%s\n", date_fmt_buf);
2848 /* test the 1st enumerated format */
2849 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2850 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2851 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2852 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2855 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2856 date_fmt_buf[0] = 0;
2857 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2858 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2859 trace("%s\n", date_fmt_buf);
2860 /* test the 1st enumerated format */
2861 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2862 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2863 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2864 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2866 trace("EnumDateFormatsA DATE_LONGDATE\n");
2867 date_fmt_buf[0] = 0;
2868 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2869 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2870 trace("%s\n", date_fmt_buf);
2871 /* test the 1st enumerated format */
2872 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2873 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2874 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2875 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2877 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2878 date_fmt_buf[0] = 0;
2879 SetLastError(0xdeadbeef);
2880 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2881 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2883 skip("DATE_YEARMONTH is only present on W2K and later\n");
2884 return;
2886 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2887 trace("%s\n", date_fmt_buf);
2888 /* test the 1st enumerated format */
2889 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2890 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2891 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2892 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2893 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2896 static void test_EnumTimeFormatsA(void)
2898 char *p, buf[256];
2899 BOOL ret;
2900 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2902 trace("EnumTimeFormatsA 0\n");
2903 date_fmt_buf[0] = 0;
2904 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2905 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2906 trace("%s\n", date_fmt_buf);
2907 /* test the 1st enumerated format */
2908 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2909 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2910 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2911 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2913 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2914 date_fmt_buf[0] = 0;
2915 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2916 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2917 trace("%s\n", date_fmt_buf);
2918 /* test the 1st enumerated format */
2919 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2920 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2921 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2922 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2925 static void test_GetCPInfo(void)
2927 BOOL ret;
2928 CPINFO cpinfo;
2930 SetLastError(0xdeadbeef);
2931 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2932 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2933 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2934 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2936 SetLastError(0xdeadbeef);
2937 ret = GetCPInfo(CP_UTF7, &cpinfo);
2938 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2940 skip("Codepage CP_UTF7 is not installed/available\n");
2942 else
2944 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2945 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2946 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2947 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2948 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2949 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2952 SetLastError(0xdeadbeef);
2953 ret = GetCPInfo(CP_UTF8, &cpinfo);
2954 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2956 skip("Codepage CP_UTF8 is not installed/available\n");
2958 else
2960 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2961 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2962 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2963 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2964 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2965 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2966 "expected 4, got %u\n", cpinfo.MaxCharSize);
2971 * The CT_TYPE1 has varied over windows version.
2972 * The current target for correct behavior is windows 7.
2973 * There was a big shift between windows 2000 (first introduced) and windows Xp
2974 * Most of the old values below are from windows 2000.
2975 * A smaller subset of changes happened between windows Xp and Window vista/7
2977 static void test_GetStringTypeW(void)
2979 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2980 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2981 C1_SPACE | C1_BLANK | C1_DEFINED,
2982 C1_SPACE | C1_BLANK | C1_DEFINED,
2983 C1_SPACE | C1_BLANK | C1_DEFINED,
2984 C1_CNTRL | C1_BLANK | C1_DEFINED};
2985 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2986 C1_SPACE | C1_BLANK,
2987 C1_SPACE | C1_BLANK,
2988 C1_SPACE | C1_BLANK,
2989 C1_SPACE | C1_BLANK};
2991 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2993 /* Lu, Ll, Lt */
2994 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2995 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2996 C1_LOWER | C1_ALPHA,
2997 C1_UPPER | C1_LOWER | C1_ALPHA,
2998 C1_ALPHA};
3000 /* Sk, Sk, Mn, So, Me */
3001 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3002 /* Sc, Sm, No,*/
3003 0xffe0, 0xffe9, 0x2153};
3005 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3006 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3007 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3008 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3009 C1_ALPHA | C1_DEFINED,
3010 C1_CNTRL | C1_DEFINED,
3011 C1_PUNCT | C1_DEFINED,
3012 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3013 C1_ALPHA | C1_LOWER | C1_DEFINED,
3014 C1_ALPHA | C1_DEFINED };
3015 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3016 C1_ALPHA | C1_DEFINED,
3017 C1_CNTRL | C1_DEFINED,
3018 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3019 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3020 C1_ALPHA | C1_DEFINED,
3021 C1_DEFINED
3023 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3024 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3026 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3027 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3028 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3029 static const WCHAR lower_special[] = {0x2071, 0x207f};
3030 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3031 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3032 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3033 0xfff9, 0xfffa, 0xfffb};
3034 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3036 WORD types[20];
3037 int i;
3039 memset(types,0,sizeof(types));
3040 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3041 for (i = 0; i < 5; i++)
3042 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]);
3044 memset(types,0,sizeof(types));
3045 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3046 for (i = 0; i < 3; i++)
3047 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]));
3048 memset(types,0,sizeof(types));
3049 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3050 for (i = 0; i < 5; i++)
3051 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3053 memset(types,0,sizeof(types));
3054 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3055 for (i = 0; i < 8; i++)
3056 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);
3058 memset(types,0,sizeof(types));
3059 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3060 for (i = 0; i < 7; i++)
3061 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]);
3063 memset(types,0,sizeof(types));
3064 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3065 for (i = 0; i < 7; i++)
3066 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));
3069 memset(types,0,sizeof(types));
3070 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3071 for (i = 0; i < 12; i++)
3072 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);
3074 memset(types,0,sizeof(types));
3075 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3076 for (i = 0; i < 3; i++)
3077 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);
3079 memset(types,0,sizeof(types));
3080 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3081 for (i = 0; i < 2; i++)
3082 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);
3084 memset(types,0,sizeof(types));
3085 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3086 for (i = 0; i < 20; i++)
3087 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);
3089 memset(types,0,sizeof(types));
3090 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3091 for (i = 0; i < 3; i++)
3092 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 );
3095 static void test_IdnToNameprepUnicode(void)
3097 struct {
3098 DWORD in_len;
3099 const WCHAR in[64];
3100 DWORD ret;
3101 const WCHAR out[64];
3102 DWORD flags;
3103 DWORD err;
3104 DWORD todo;
3105 } test_data[] = {
3107 5, {'t','e','s','t',0},
3108 5, {'t','e','s','t',0},
3109 0, 0xdeadbeef
3112 3, {'a',0xe111,'b'},
3113 0, {0},
3114 0, ERROR_INVALID_NAME
3117 4, {'t',0,'e',0},
3118 0, {0},
3119 0, ERROR_INVALID_NAME
3122 1, {'T',0},
3123 1, {'T',0},
3124 0, 0xdeadbeef
3127 1, {0},
3128 0, {0},
3129 0, ERROR_INVALID_NAME
3132 6, {' ','-','/','[',']',0},
3133 6, {' ','-','/','[',']',0},
3134 0, 0xdeadbeef
3137 3, {'a','-','a'},
3138 3, {'a','-','a'},
3139 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3142 3, {'a','a','-'},
3143 0, {0},
3144 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3146 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3147 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3148 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3149 0, 0xdeadbeef, TRUE
3152 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3153 2, {'t',0},
3154 0, 0xdeadbeef
3156 { /* Another example of incorrectly working FoldString (composition) */
3157 2, {0x3b0, 0},
3158 2, {0x3b0, 0},
3159 0, 0xdeadbeef, TRUE
3162 2, {0x221, 0},
3163 0, {0},
3164 0, ERROR_NO_UNICODE_TRANSLATION
3167 2, {0x221, 0},
3168 2, {0x221, 0},
3169 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3172 5, {'a','.','.','a',0},
3173 0, {0},
3174 0, ERROR_INVALID_NAME
3177 3, {'a','.',0},
3178 3, {'a','.',0},
3179 0, 0xdeadbeef
3183 WCHAR buf[1024];
3184 DWORD i, ret, err;
3186 if (!pIdnToNameprepUnicode)
3188 win_skip("IdnToNameprepUnicode is not available\n");
3189 return;
3192 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3193 test_data[0].in_len, NULL, 0);
3194 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3196 SetLastError(0xdeadbeef);
3197 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3198 test_data[1].in_len, NULL, 0);
3199 err = GetLastError();
3200 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3201 ok(err == test_data[1].err, "err = %d\n", err);
3203 SetLastError(0xdeadbeef);
3204 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3205 buf, sizeof(buf)/sizeof(WCHAR));
3206 err = GetLastError();
3207 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3208 ok(err == 0xdeadbeef, "err = %d\n", err);
3210 SetLastError(0xdeadbeef);
3211 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3212 buf, sizeof(buf)/sizeof(WCHAR));
3213 err = GetLastError();
3214 ok(ret == 0, "ret = %d\n", ret);
3215 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3217 SetLastError(0xdeadbeef);
3218 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3219 buf, sizeof(buf)/sizeof(WCHAR));
3220 err = GetLastError();
3221 ok(ret == 0, "ret = %d\n", ret);
3222 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3224 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3225 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3226 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3228 SetLastError(0xdeadbeef);
3229 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3230 err = GetLastError();
3231 ok(ret == 0, "ret = %d\n", ret);
3232 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3234 SetLastError(0xdeadbeef);
3235 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3236 err = GetLastError();
3237 ok(ret == 0, "ret = %d\n", ret);
3238 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3240 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3242 SetLastError(0xdeadbeef);
3243 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3244 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3245 err = GetLastError();
3246 if(!test_data[i].todo) {
3247 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3248 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3249 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3250 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3251 }else {
3252 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3253 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3258 static void test_IdnToAscii(void)
3260 struct {
3261 DWORD in_len;
3262 const WCHAR in[64];
3263 DWORD ret;
3264 const WCHAR out[64];
3265 DWORD flags;
3266 DWORD err;
3267 } test_data[] = {
3269 5, {'T','e','s','t',0},
3270 5, {'T','e','s','t',0},
3271 0, 0xdeadbeef
3274 5, {'T','e',0x017c,'s','t',0},
3275 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3276 0, 0xdeadbeef
3279 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3280 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3281 0, 0xdeadbeef
3284 3, {0x0105,'.',0},
3285 9, {'x','n','-','-','2','d','a','.',0},
3286 0, 0xdeadbeef
3289 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3290 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3291 0, 0xdeadbeef
3294 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3295 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3296 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3297 0, 0xdeadbeef
3300 2, {0x221,0},
3301 8, {'x','n','-','-','6','l','a',0},
3302 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3306 WCHAR buf[1024];
3307 DWORD i, ret, err;
3309 if (!pIdnToAscii)
3311 win_skip("IdnToAscii is not available\n");
3312 return;
3315 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3317 SetLastError(0xdeadbeef);
3318 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3319 test_data[i].in_len, buf, sizeof(buf));
3320 err = GetLastError();
3321 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3322 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3323 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3324 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3328 static void test_IdnToUnicode(void)
3330 struct {
3331 DWORD in_len;
3332 const WCHAR in[64];
3333 DWORD ret;
3334 const WCHAR out[64];
3335 DWORD flags;
3336 DWORD err;
3337 } test_data[] = {
3339 5, {'T','e','s','.',0},
3340 5, {'T','e','s','.',0},
3341 0, 0xdeadbeef
3344 2, {0x105,0},
3345 0, {0},
3346 0, ERROR_INVALID_NAME
3349 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3350 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3351 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3352 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3353 0x05d1,0x05e8,0x05d9,0x05ea,0},
3354 0, 0xdeadbeef
3357 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3358 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3359 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3360 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3361 0, 0xdeadbeef
3364 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3365 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3366 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3367 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3368 0, {0},
3369 0, ERROR_INVALID_NAME
3372 8, {'x','n','-','-','6','l','a',0},
3373 2, {0x221,0},
3374 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3378 WCHAR buf[1024];
3379 DWORD i, ret, err;
3381 if (!pIdnToUnicode)
3383 win_skip("IdnToUnicode is not available\n");
3384 return;
3387 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3389 SetLastError(0xdeadbeef);
3390 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3391 test_data[i].in_len, buf, sizeof(buf));
3392 err = GetLastError();
3393 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3394 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3395 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3396 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3400 static void test_GetLocaleInfoEx(void)
3402 static const WCHAR enW[] = {'e','n',0};
3403 WCHAR bufferW[80];
3404 INT ret;
3406 if (!pGetLocaleInfoEx)
3408 win_skip("GetLocaleInfoEx not supported\n");
3409 return;
3412 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3413 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3414 if (ret)
3416 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3417 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3418 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3419 static const WCHAR usaW[] = {'U','S','A',0};
3420 static const WCHAR enuW[] = {'E','N','U',0};
3421 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3422 DWORD val;
3424 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3425 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3427 SetLastError(0xdeadbeef);
3428 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
3429 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
3431 SetLastError(0xdeadbeef);
3432 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
3433 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
3435 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3436 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3437 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3439 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3440 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3441 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3443 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3444 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3445 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3447 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3448 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3449 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
3450 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
3452 skip("Non-English locale\n");
3454 else
3455 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3457 bufferW[0] = 0;
3458 SetLastError(0xdeadbeef);
3459 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3460 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3462 while (*ptr->name)
3464 val = 0;
3465 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3466 if (ptr->todo)
3467 todo_wine
3468 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3469 else
3470 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3471 bufferW[0] = 0;
3472 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3473 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
3474 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3475 ptr++;
3480 static void test_IsValidLocaleName(void)
3482 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3483 static const WCHAR zzW[] = {'z','z',0};
3484 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3485 BOOL ret;
3487 if (!pIsValidLocaleName)
3489 win_skip("IsValidLocaleName not supported\n");
3490 return;
3493 ret = pIsValidLocaleName(enusW);
3494 ok(ret, "IsValidLocaleName failed\n");
3495 ret = pIsValidLocaleName(zzW);
3496 ok(!ret, "IsValidLocaleName should have failed\n");
3497 ret = pIsValidLocaleName(zzzzW);
3498 ok(!ret, "IsValidLocaleName should have failed\n");
3501 static void test_CompareStringOrdinal(void)
3503 INT ret;
3504 WCHAR test1[] = { 't','e','s','t',0 };
3505 WCHAR test2[] = { 'T','e','S','t',0 };
3506 WCHAR test3[] = { 't','e','s','t','3',0 };
3507 WCHAR null1[] = { 'a',0,'a',0 };
3508 WCHAR null2[] = { 'a',0,'b',0 };
3509 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
3510 WCHAR bills2[] = { 'b','i','l','l','s',0 };
3511 WCHAR coop1[] = { 'c','o','-','o','p',0 };
3512 WCHAR coop2[] = { 'c','o','o','p',0 };
3513 WCHAR nonascii1[] = { 0x0102,0 };
3514 WCHAR nonascii2[] = { 0x0201,0 };
3516 if (!pCompareStringOrdinal)
3518 win_skip("CompareStringOrdinal not supported\n");
3519 return;
3522 /* Check errors */
3523 SetLastError(0xdeadbeef);
3524 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
3525 ok(!ret, "Got %u, expected 0\n", ret);
3526 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3527 SetLastError(0xdeadbeef);
3528 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
3529 ok(!ret, "Got %u, expected 0\n", ret);
3530 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3531 SetLastError(0xdeadbeef);
3532 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
3533 ok(!ret, "Got %u, expected 0\n", ret);
3534 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3536 /* Check case */
3537 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
3538 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3539 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
3540 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3541 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
3542 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3543 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
3544 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3546 /* Check different sizes */
3547 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
3548 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3549 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
3550 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3552 /* Check null character */
3553 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
3554 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3555 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
3556 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3557 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
3558 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3559 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
3560 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3562 /* Check ordinal behaviour */
3563 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
3564 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3565 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
3566 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3567 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
3568 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3569 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
3570 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3573 START_TEST(locale)
3575 InitFunctionPointers();
3577 test_EnumTimeFormatsA();
3578 test_EnumDateFormatsA();
3579 test_GetLocaleInfoA();
3580 test_GetLocaleInfoW();
3581 test_GetLocaleInfoEx();
3582 test_GetTimeFormatA();
3583 test_GetDateFormatA();
3584 test_GetDateFormatW();
3585 test_GetCurrencyFormatA(); /* Also tests the W version */
3586 test_GetNumberFormatA(); /* Also tests the W version */
3587 test_CompareStringA();
3588 test_LCMapStringA();
3589 test_LCMapStringW();
3590 test_LCMapStringEx();
3591 test_LocaleNameToLCID();
3592 test_FoldStringA();
3593 test_FoldStringW();
3594 test_ConvertDefaultLocale();
3595 test_EnumSystemLanguageGroupsA();
3596 test_EnumSystemLocalesEx();
3597 test_EnumLanguageGroupLocalesA();
3598 test_SetLocaleInfoA();
3599 test_EnumUILanguageA();
3600 test_GetCPInfo();
3601 test_GetStringTypeW();
3602 test_IdnToNameprepUnicode();
3603 test_IdnToAscii();
3604 test_IdnToUnicode();
3605 test_IsValidLocaleName();
3606 test_CompareStringOrdinal();
3607 /* this requires collation table patch to make it MS compatible */
3608 if (0) test_sorting();