Release 1.6-rc2.
[wine/testsucceed.git] / dlls / kernel32 / tests / locale.c
blob772d13bfc6e8c4bdc4eacfe3cc74381336f4ae5d
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 char a[256];
1332 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1334 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1336 const struct comparestringa_entry *entry = &comparestringa_data[i];
1338 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1339 entry->second, entry->second_len);
1340 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1343 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1344 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1346 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1347 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1349 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1350 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1352 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1353 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1355 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1357 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1358 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1360 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1361 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1363 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1364 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1366 /* test for CompareStringA flags */
1367 SetLastError(0xdeadbeef);
1368 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1369 ok(GetLastError() == ERROR_INVALID_FLAGS,
1370 "unexpected error code %d\n", GetLastError());
1371 ok(!ret, "CompareStringA must fail with invalid flag\n");
1373 SetLastError(0xdeadbeef);
1374 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1375 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1376 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1377 /* end of test for CompareStringA flags */
1379 ret = lstrcmpA("", "");
1380 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1382 ret = lstrcmpA(NULL, NULL);
1383 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1385 ret = lstrcmpA("", NULL);
1386 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1388 ret = lstrcmpA(NULL, "");
1389 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1392 if (0) { /* this requires collation table patch to make it MS compatible */
1393 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1394 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1396 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1397 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1399 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1400 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1402 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1403 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1405 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1406 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1408 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1409 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1411 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1412 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1414 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1415 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1417 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1418 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1420 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1421 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1423 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1424 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1426 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1427 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1431 /* WinXP handles embedded NULLs differently than earlier versions */
1432 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1433 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1435 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1436 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);
1438 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1439 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1441 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1442 ok(ret == CSTR_EQUAL || /* win2k */
1443 ret == CSTR_GREATER_THAN,
1444 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1446 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1447 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1449 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1450 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1452 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1453 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1455 ret = lstrcmpi("#", ".");
1456 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1458 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1460 /* \xB9 character lies between a and b */
1461 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1462 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1463 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1464 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1466 memset(a, 'a', sizeof(a));
1467 SetLastError(0xdeadbeef);
1468 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1469 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1470 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1473 static void test_LCMapStringA(void)
1475 int ret, ret2;
1476 char buf[256], buf2[256];
1477 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1478 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1479 static const char symbols_stripped[] = "justateststring1";
1481 SetLastError(0xdeadbeef);
1482 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1483 lower_case, -1, buf, sizeof(buf));
1484 ok(ret == lstrlenA(lower_case) + 1,
1485 "ret %d, error %d, expected value %d\n",
1486 ret, GetLastError(), lstrlenA(lower_case) + 1);
1487 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1489 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1490 upper_case, -1, buf, sizeof(buf));
1491 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1492 ok(GetLastError() == ERROR_INVALID_FLAGS,
1493 "unexpected error code %d\n", GetLastError());
1495 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1496 upper_case, -1, buf, sizeof(buf));
1497 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1498 ok(GetLastError() == ERROR_INVALID_FLAGS,
1499 "unexpected error code %d\n", GetLastError());
1501 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1502 upper_case, -1, buf, sizeof(buf));
1503 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1504 ok(GetLastError() == ERROR_INVALID_FLAGS,
1505 "unexpected error code %d\n", GetLastError());
1507 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1508 upper_case, -1, buf, sizeof(buf));
1509 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1510 ok(GetLastError() == ERROR_INVALID_FLAGS,
1511 "unexpected error code %d\n", GetLastError());
1513 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1514 SetLastError(0xdeadbeef);
1515 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1516 upper_case, -1, buf, sizeof(buf));
1517 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1518 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1520 /* test LCMAP_LOWERCASE */
1521 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1522 upper_case, -1, buf, sizeof(buf));
1523 ok(ret == lstrlenA(upper_case) + 1,
1524 "ret %d, error %d, expected value %d\n",
1525 ret, GetLastError(), lstrlenA(upper_case) + 1);
1526 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1528 /* test LCMAP_UPPERCASE */
1529 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1530 lower_case, -1, buf, sizeof(buf));
1531 ok(ret == lstrlenA(lower_case) + 1,
1532 "ret %d, error %d, expected value %d\n",
1533 ret, GetLastError(), lstrlenA(lower_case) + 1);
1534 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1536 /* test buffer overflow */
1537 SetLastError(0xdeadbeef);
1538 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1539 lower_case, -1, buf, 4);
1540 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1541 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1543 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1544 lstrcpyA(buf, lower_case);
1545 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1546 buf, -1, buf, sizeof(buf));
1547 if (!ret) /* Win9x */
1548 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1549 else
1551 ok(ret == lstrlenA(lower_case) + 1,
1552 "ret %d, error %d, expected value %d\n",
1553 ret, GetLastError(), lstrlenA(lower_case) + 1);
1554 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1556 lstrcpyA(buf, upper_case);
1557 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1558 buf, -1, buf, sizeof(buf));
1559 if (!ret) /* Win9x */
1560 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1561 else
1563 ok(ret == lstrlenA(upper_case) + 1,
1564 "ret %d, error %d, expected value %d\n",
1565 ret, GetLastError(), lstrlenA(lower_case) + 1);
1566 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1569 /* otherwise src == dst should fail */
1570 SetLastError(0xdeadbeef);
1571 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1572 buf, 10, buf, sizeof(buf));
1573 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1574 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1575 "unexpected error code %d\n", GetLastError());
1576 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1578 /* test whether '\0' is always appended */
1579 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1580 upper_case, -1, buf, sizeof(buf));
1581 ok(ret, "LCMapStringA must succeed\n");
1582 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1583 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1584 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1585 ok(ret2, "LCMapStringA must succeed\n");
1586 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1587 ok(ret == ret2, "lengths of sort keys must be equal\n");
1588 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1590 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1591 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1592 upper_case, -1, buf, sizeof(buf));
1593 ok(ret, "LCMapStringA must succeed\n");
1594 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1595 lower_case, -1, buf2, sizeof(buf2));
1596 ok(ret2, "LCMapStringA must succeed\n");
1597 ok(ret == ret2, "lengths of sort keys must be equal\n");
1598 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1600 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1601 results from plain LCMAP_SORTKEY on Vista */
1603 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1604 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1605 lower_case, -1, buf, sizeof(buf));
1606 ok(ret, "LCMapStringA must succeed\n");
1607 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1608 symbols_stripped, -1, buf2, sizeof(buf2));
1609 ok(ret2, "LCMapStringA must succeed\n");
1610 ok(ret == ret2, "lengths of sort keys must be equal\n");
1611 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1613 /* test NORM_IGNORENONSPACE */
1614 lstrcpyA(buf, "foo");
1615 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1616 lower_case, -1, buf, sizeof(buf));
1617 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1618 lstrlenA(lower_case) + 1, ret);
1619 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1621 /* test NORM_IGNORESYMBOLS */
1622 lstrcpyA(buf, "foo");
1623 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1624 lower_case, -1, buf, sizeof(buf));
1625 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1626 lstrlenA(symbols_stripped) + 1, ret);
1627 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1629 /* test srclen = 0 */
1630 SetLastError(0xdeadbeef);
1631 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1632 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1633 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1634 "unexpected error code %d\n", GetLastError());
1637 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1639 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1641 int ret, ret2;
1642 WCHAR buf[256], buf2[256];
1643 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1645 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1646 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1647 if (broken(ret))
1648 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1649 else
1651 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1652 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1653 func_name, GetLastError());
1656 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1657 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1658 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1659 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1660 func_name, GetLastError());
1662 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1663 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1664 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1665 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1666 func_name, GetLastError());
1668 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1669 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1670 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1671 func_name);
1672 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1673 func_name, GetLastError());
1675 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1676 SetLastError(0xdeadbeef);
1677 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1678 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1679 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1680 func_name, GetLastError());
1681 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1683 /* test LCMAP_LOWERCASE */
1684 ret = func_ptr(LCMAP_LOWERCASE,
1685 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1686 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1687 ret, GetLastError(), lstrlenW(upper_case) + 1);
1688 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1690 /* test LCMAP_UPPERCASE */
1691 ret = func_ptr(LCMAP_UPPERCASE,
1692 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1693 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1694 ret, GetLastError(), lstrlenW(lower_case) + 1);
1695 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1697 /* test buffer overflow */
1698 SetLastError(0xdeadbeef);
1699 ret = func_ptr(LCMAP_UPPERCASE,
1700 lower_case, -1, buf, 4);
1701 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1702 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1704 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1705 lstrcpyW(buf, lower_case);
1706 ret = func_ptr(LCMAP_UPPERCASE,
1707 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1708 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1709 ret, GetLastError(), lstrlenW(lower_case) + 1);
1710 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1712 lstrcpyW(buf, upper_case);
1713 ret = func_ptr(LCMAP_LOWERCASE,
1714 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1715 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1716 ret, GetLastError(), lstrlenW(lower_case) + 1);
1717 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1719 /* otherwise src == dst should fail */
1720 SetLastError(0xdeadbeef);
1721 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1722 buf, 10, buf, sizeof(buf));
1723 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1724 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1725 "%s unexpected error code %d\n", func_name, GetLastError());
1726 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1728 /* test whether '\0' is always appended */
1729 ret = func_ptr(LCMAP_SORTKEY,
1730 upper_case, -1, buf, sizeof(buf));
1731 ok(ret, "%s func_ptr must succeed\n", func_name);
1732 ret2 = func_ptr(LCMAP_SORTKEY,
1733 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1734 ok(ret, "%s func_ptr must succeed\n", func_name);
1735 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1736 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1738 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1739 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1740 upper_case, -1, buf, sizeof(buf));
1741 ok(ret, "%s func_ptr must succeed\n", func_name);
1742 ret2 = func_ptr(LCMAP_SORTKEY,
1743 lower_case, -1, buf2, sizeof(buf2));
1744 ok(ret2, "%s func_ptr must succeed\n", func_name);
1745 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1746 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1748 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1749 results from plain LCMAP_SORTKEY on Vista */
1751 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1752 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1753 lower_case, -1, buf, sizeof(buf));
1754 ok(ret, "%s func_ptr must succeed\n", func_name);
1755 ret2 = func_ptr(LCMAP_SORTKEY,
1756 symbols_stripped, -1, buf2, sizeof(buf2));
1757 ok(ret2, "%s func_ptr must succeed\n", func_name);
1758 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1759 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1761 /* test NORM_IGNORENONSPACE */
1762 lstrcpyW(buf, fooW);
1763 ret = func_ptr(NORM_IGNORENONSPACE,
1764 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1765 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1766 lstrlenW(lower_case) + 1, ret);
1767 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1769 /* test NORM_IGNORESYMBOLS */
1770 lstrcpyW(buf, fooW);
1771 ret = func_ptr(NORM_IGNORESYMBOLS,
1772 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1773 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1774 lstrlenW(symbols_stripped) + 1, ret);
1775 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1777 /* test srclen = 0 */
1778 SetLastError(0xdeadbeef);
1779 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1780 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1781 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1782 "%s unexpected error code %d\n", func_name, GetLastError());
1785 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1787 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1790 static void test_LCMapStringW(void)
1792 int ret;
1793 WCHAR buf[256];
1795 trace("testing LCMapStringW\n");
1797 SetLastError(0xdeadbeef);
1798 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1799 todo_wine {
1800 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1801 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1804 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1807 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1809 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1812 static void test_LCMapStringEx(void)
1814 int ret;
1815 WCHAR buf[256];
1817 if (!pLCMapStringEx)
1819 win_skip( "LCMapStringEx not available\n" );
1820 return;
1823 trace("testing LCMapStringEx\n");
1825 SetLastError(0xdeadbeef);
1826 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
1827 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1828 todo_wine {
1829 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1830 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1833 /* test reserved parameters */
1834 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1835 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1836 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1837 ret, GetLastError(), lstrlenW(upper_case) + 1);
1838 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1840 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1841 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1842 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1843 ret, GetLastError(), lstrlenW(upper_case) + 1);
1844 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1846 /* crashes on native */
1847 if(0)
1848 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1849 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1851 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1854 struct neutralsublang_name_t {
1855 WCHAR name[3];
1856 LCID lcid;
1857 int todo;
1860 static const struct neutralsublang_name_t neutralsublang_names[] = {
1861 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1862 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1863 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1864 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1865 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1866 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1867 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1868 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1869 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1870 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1871 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1872 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1873 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1874 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1875 { {0} }
1878 static void test_LocaleNameToLCID(void)
1880 LCID lcid;
1881 INT ret;
1882 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1883 static const WCHAR enW[] = {'e','n',0};
1885 if (!pLocaleNameToLCID)
1887 win_skip( "LocaleNameToLCID not available\n" );
1888 return;
1891 /* special cases */
1892 buffer[0] = 0;
1893 SetLastError(0xdeadbeef);
1894 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1895 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1896 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
1897 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1898 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1899 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1901 buffer[0] = 0;
1902 SetLastError(0xdeadbeef);
1903 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1904 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1905 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
1906 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1907 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1908 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1910 buffer[0] = 0;
1911 SetLastError(0xdeadbeef);
1912 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1913 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1914 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1915 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1916 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1918 /* bad name */
1919 SetLastError(0xdeadbeef);
1920 lcid = pLocaleNameToLCID(fooW, 0);
1921 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1922 "Expected lcid == 0, got got %08x, error %d\n", lcid, GetLastError());
1924 /* english neutral name */
1925 lcid = pLocaleNameToLCID(enW, 0);
1926 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1927 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1928 if (lcid)
1930 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1932 while (*ptr->name)
1934 lcid = pLocaleNameToLCID(ptr->name, 0);
1935 if (ptr->todo)
1936 todo_wine
1937 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1938 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1939 else
1940 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1941 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1943 *buffer = 0;
1944 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
1945 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
1946 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
1947 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
1949 ptr++;
1954 /* this requires collation table patch to make it MS compatible */
1955 static const char * const strings_sorted[] =
1957 "'",
1958 "-",
1959 "!",
1960 "\"",
1961 ".",
1962 ":",
1963 "\\",
1964 "_",
1965 "`",
1966 "{",
1967 "}",
1968 "+",
1969 "0",
1970 "1",
1971 "2",
1972 "3",
1973 "4",
1974 "5",
1975 "6",
1976 "7",
1977 "8",
1978 "9",
1979 "a",
1980 "A",
1981 "b",
1982 "B",
1983 "c",
1987 static const char * const strings[] =
1989 "C",
1990 "\"",
1991 "9",
1992 "'",
1993 "}",
1994 "-",
1995 "7",
1996 "+",
1997 "`",
1998 "1",
1999 "a",
2000 "5",
2001 "\\",
2002 "8",
2003 "B",
2004 "3",
2005 "_",
2006 "6",
2007 "{",
2008 "2",
2009 "c",
2010 "4",
2011 "!",
2012 "0",
2013 "A",
2014 ":",
2015 "b",
2019 static int compare_string1(const void *e1, const void *e2)
2021 const char *s1 = *(const char *const *)e1;
2022 const char *s2 = *(const char *const *)e2;
2024 return lstrcmpA(s1, s2);
2027 static int compare_string2(const void *e1, const void *e2)
2029 const char *s1 = *(const char *const *)e1;
2030 const char *s2 = *(const char *const *)e2;
2032 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2035 static int compare_string3(const void *e1, const void *e2)
2037 const char *s1 = *(const char *const *)e1;
2038 const char *s2 = *(const char *const *)e2;
2039 char key1[256], key2[256];
2041 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2042 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2043 return strcmp(key1, key2);
2046 static void test_sorting(void)
2048 char buf[256];
2049 char **str_buf = (char **)buf;
2050 int i;
2052 assert(sizeof(buf) >= sizeof(strings));
2054 /* 1. sort using lstrcmpA */
2055 memcpy(buf, strings, sizeof(strings));
2056 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2057 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2059 ok(!strcmp(strings_sorted[i], str_buf[i]),
2060 "qsort using lstrcmpA failed for element %d\n", i);
2062 /* 2. sort using CompareStringA */
2063 memcpy(buf, strings, sizeof(strings));
2064 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2065 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2067 ok(!strcmp(strings_sorted[i], str_buf[i]),
2068 "qsort using CompareStringA failed for element %d\n", i);
2070 /* 3. sort using sort keys */
2071 memcpy(buf, strings, sizeof(strings));
2072 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2073 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2075 ok(!strcmp(strings_sorted[i], str_buf[i]),
2076 "qsort using sort keys failed for element %d\n", i);
2080 static void test_FoldStringA(void)
2082 int ret, i, j;
2083 BOOL is_special;
2084 char src[256], dst[256];
2085 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2086 static const char digits_dst[] = { '1','2','3','\0' };
2087 static const char composite_src[] =
2089 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2090 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2091 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2092 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2093 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2094 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2095 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2096 0xfb,0xfc,0xfd,0xff,'\0'
2098 static const char composite_dst[] =
2100 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2101 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2102 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2103 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2104 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2105 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2106 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2107 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2108 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2109 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2110 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2111 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2112 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2113 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2114 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2116 static const char composite_dst_alt[] =
2118 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2119 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2120 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2121 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2122 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2123 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2124 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2125 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2126 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2127 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2128 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2129 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2130 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2131 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2132 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2134 static const char ligatures_src[] =
2136 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2138 static const char ligatures_dst[] =
2140 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2142 static const struct special
2144 char src;
2145 char dst[4];
2146 } foldczone_special[] =
2148 /* src dst */
2149 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2150 { 0x98, { 0x20, 0x7e, 0x00 } },
2151 { 0x99, { 0x54, 0x4d, 0x00 } },
2152 { 0xa0, { 0x20, 0x00 } },
2153 { 0xa8, { 0x20, 0xa8, 0x00 } },
2154 { 0xaa, { 0x61, 0x00 } },
2155 { 0xaf, { 0x20, 0xaf, 0x00 } },
2156 { 0xb2, { 0x32, 0x00 } },
2157 { 0xb3, { 0x33, 0x00 } },
2158 { 0xb4, { 0x20, 0xb4, 0x00 } },
2159 { 0xb8, { 0x20, 0xb8, 0x00 } },
2160 { 0xb9, { 0x31, 0x00 } },
2161 { 0xba, { 0x6f, 0x00 } },
2162 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2163 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2164 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2165 { 0x00 }
2168 if (!pFoldStringA)
2169 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2171 /* these tests are locale specific */
2172 if (GetACP() != 1252)
2174 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2175 return;
2178 /* MAP_FOLDDIGITS */
2179 SetLastError(0);
2180 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2181 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2183 win_skip("FoldStringA is not implemented\n");
2184 return;
2186 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2187 ok(strcmp(dst, digits_dst) == 0,
2188 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2189 for (i = 1; i < 256; i++)
2191 if (!strchr(digits_src, i))
2193 src[0] = i;
2194 src[1] = '\0';
2195 SetLastError(0);
2196 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2197 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2198 ok(dst[0] == src[0],
2199 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2203 /* MAP_EXPAND_LIGATURES */
2204 SetLastError(0);
2205 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2206 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2207 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2208 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2209 ok(strcmp(dst, ligatures_dst) == 0,
2210 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2211 for (i = 1; i < 256; i++)
2213 if (!strchr(ligatures_src, i))
2215 src[0] = i;
2216 src[1] = '\0';
2217 SetLastError(0);
2218 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2219 if (ret == 3)
2221 /* Vista */
2222 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2223 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2224 "Got %s for %d\n", dst, i);
2226 else
2228 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2229 ok(dst[0] == src[0],
2230 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2236 /* MAP_COMPOSITE */
2237 SetLastError(0);
2238 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2239 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2240 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2241 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2242 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2244 for (i = 1; i < 256; i++)
2246 if (!strchr(composite_src, i))
2248 src[0] = i;
2249 src[1] = '\0';
2250 SetLastError(0);
2251 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2252 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2253 ok(dst[0] == src[0],
2254 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2255 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2259 /* MAP_FOLDCZONE */
2260 for (i = 1; i < 256; i++)
2262 src[0] = i;
2263 src[1] = '\0';
2264 SetLastError(0);
2265 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2266 is_special = FALSE;
2267 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2269 if (foldczone_special[j].src == src[0])
2271 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2272 "Expected ret == 2 or %d, got %d, error %d\n",
2273 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2274 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2275 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2276 (unsigned char)src[0]);
2277 is_special = TRUE;
2280 if (! is_special)
2282 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2283 ok(src[0] == dst[0],
2284 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2285 (unsigned char)src[0], (unsigned char)dst[0]);
2289 /* MAP_PRECOMPOSED */
2290 for (i = 1; i < 256; i++)
2292 src[0] = i;
2293 src[1] = '\0';
2294 SetLastError(0);
2295 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2296 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2297 ok(src[0] == dst[0],
2298 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2299 (unsigned char)src[0], (unsigned char)dst[0]);
2303 static void test_FoldStringW(void)
2305 int ret;
2306 unsigned int i, j;
2307 WCHAR src[256], dst[256], ch, prev_ch = 1;
2308 static const DWORD badFlags[] =
2311 MAP_PRECOMPOSED|MAP_COMPOSITE,
2312 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2313 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2315 /* Ranges of digits 0-9 : Must be sorted! */
2316 static const WCHAR digitRanges[] =
2318 0x0030, /* '0'-'9' */
2319 0x0660, /* Eastern Arabic */
2320 0x06F0, /* Arabic - Hindu */
2321 0x0966, /* Devengari */
2322 0x09E6, /* Bengalii */
2323 0x0A66, /* Gurmukhi */
2324 0x0AE6, /* Gujarati */
2325 0x0B66, /* Oriya */
2326 0x0BE6, /* Tamil - No 0 */
2327 0x0C66, /* Telugu */
2328 0x0CE6, /* Kannada */
2329 0x0D66, /* Maylayalam */
2330 0x0E50, /* Thai */
2331 0x0ED0, /* Laos */
2332 0x0F29, /* Tibet - 0 is out of sequence */
2333 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2334 0x2080, /* Subscript */
2335 0x245F, /* Circled - 0 is out of sequence */
2336 0x2473, /* Bracketed */
2337 0x2487, /* Full stop */
2338 0x2775, /* Inverted circled - No 0 */
2339 0x277F, /* Patterned circled - No 0 */
2340 0x2789, /* Inverted Patterned circled - No 0 */
2341 0x3020, /* Hangzhou */
2342 0xff10, /* Pliene chasse (?) */
2343 0xffff /* Terminator */
2345 /* Digits which are represented, but out of sequence */
2346 static const WCHAR outOfSequenceDigits[] =
2348 0xB9, /* Superscript 1 */
2349 0xB2, /* Superscript 2 */
2350 0xB3, /* Superscript 3 */
2351 0x0F33, /* Tibetan half zero */
2352 0x24EA, /* Circled 0 */
2353 0x3007, /* Ideographic number zero */
2354 '\0' /* Terminator */
2356 /* Digits in digitRanges for which no representation is available */
2357 static const WCHAR noDigitAvailable[] =
2359 0x0BE6, /* No Tamil 0 */
2360 0x0F29, /* No Tibetan half zero (out of sequence) */
2361 0x2473, /* No Bracketed 0 */
2362 0x2487, /* No 0 Full stop */
2363 0x2775, /* No inverted circled 0 */
2364 0x277F, /* No patterned circled */
2365 0x2789, /* No inverted Patterned circled */
2366 0x3020, /* No Hangzhou 0 */
2367 '\0' /* Terminator */
2369 static const WCHAR foldczone_src[] =
2371 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2372 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2374 static const WCHAR foldczone_dst[] =
2376 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2378 static const WCHAR foldczone_todo_src[] =
2380 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2382 static const WCHAR foldczone_todo_dst[] =
2384 0x3cb,0x1f0,' ','a',0
2386 static const WCHAR foldczone_todo_broken_dst[] =
2388 0x3cb,0x1f0,0xa0,0xaa,0
2390 static const WCHAR ligatures_src[] =
2392 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2393 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2394 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2395 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2396 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2397 0xfb04, 0xfb05, 0xfb06, '\0'
2399 static const WCHAR ligatures_dst[] =
2401 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2402 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2403 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2404 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2405 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2406 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2409 if (!pFoldStringW)
2411 win_skip("FoldStringW is not available\n");
2412 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2415 /* Invalid flag combinations */
2416 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2418 src[0] = dst[0] = '\0';
2419 SetLastError(0);
2420 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2421 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2423 win_skip("FoldStringW is not implemented\n");
2424 return;
2426 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2427 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2430 /* src & dst cannot be the same */
2431 SetLastError(0);
2432 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2433 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2434 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2436 /* src can't be NULL */
2437 SetLastError(0);
2438 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2442 /* srclen can't be 0 */
2443 SetLastError(0);
2444 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2445 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2448 /* dstlen can't be < 0 */
2449 SetLastError(0);
2450 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2451 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2452 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2454 /* Ret includes terminating NUL which is appended if srclen = -1 */
2455 SetLastError(0);
2456 src[0] = 'A';
2457 src[1] = '\0';
2458 dst[0] = '\0';
2459 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2460 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2461 ok(dst[0] == 'A' && dst[1] == '\0',
2462 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2463 'A', '\0', ret, dst[0], dst[1], GetLastError());
2465 /* If size is given, result is not NUL terminated */
2466 SetLastError(0);
2467 src[0] = 'A';
2468 src[1] = 'A';
2469 dst[0] = 'X';
2470 dst[1] = 'X';
2471 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2472 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2473 ok(dst[0] == 'A' && dst[1] == 'X',
2474 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2475 'A','X', ret, dst[0], dst[1], GetLastError());
2477 /* MAP_FOLDDIGITS */
2478 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2480 /* Check everything before this range */
2481 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2483 SetLastError(0);
2484 src[0] = ch;
2485 src[1] = dst[0] = '\0';
2486 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2487 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2489 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2490 /* Wine (correctly) maps all Unicode 4.0+ digits */
2491 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2492 (ch >= 0x1369 && ch <= 0x1371),
2493 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2496 if (digitRanges[j] == 0xffff)
2497 break; /* Finished the whole code point space */
2499 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2501 WCHAR c;
2503 /* Map out of sequence characters */
2504 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2505 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2506 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2507 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2508 else c = ch;
2509 SetLastError(0);
2510 src[0] = c;
2511 src[1] = dst[0] = '\0';
2512 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2513 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2515 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2516 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2517 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2518 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2519 strchrW(noDigitAvailable, c),
2520 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2521 ch, '0' + digitRanges[j] - ch, dst[0]);
2523 prev_ch = ch;
2526 /* MAP_FOLDCZONE */
2527 SetLastError(0);
2528 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2529 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2530 "Got %d, error %d\n", ret, GetLastError());
2531 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2532 "MAP_FOLDCZONE: Expanded incorrectly\n");
2534 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2535 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2536 "Got %d, error %d\n", ret, GetLastError());
2537 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2538 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2539 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2541 /* MAP_EXPAND_LIGATURES */
2542 SetLastError(0);
2543 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2544 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2545 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2546 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2547 "Got %d, error %d\n", ret, GetLastError());
2548 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2549 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2552 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2557 #define LCID_OK(l) \
2558 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2559 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2560 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2561 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2562 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2564 static void test_ConvertDefaultLocale(void)
2566 LCID lcid;
2568 /* Doesn't change lcid, even if non default sublang/sort used */
2569 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2570 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2571 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2572 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2574 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2575 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2576 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2577 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2578 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2580 /* Invariant language is not treated specially */
2581 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2583 /* User/system default languages alone are not mapped */
2584 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2585 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2587 /* Default lcids */
2588 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2589 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2590 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2593 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2594 DWORD dwFlags, LONG_PTR lParam)
2596 trace("%08x, %s, %s, %08x, %08lx\n",
2597 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2599 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2600 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2602 /* If lParam is one, we are calling with flags defaulted from 0 */
2603 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2604 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2606 return TRUE;
2609 static void test_EnumSystemLanguageGroupsA(void)
2611 BOOL ret;
2613 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2615 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2616 return;
2619 /* No enumeration proc */
2620 SetLastError(0);
2621 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2622 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2624 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2625 return;
2627 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2628 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2630 /* Invalid flags */
2631 SetLastError(0);
2632 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2633 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2635 /* No flags - defaults to LGRPID_INSTALLED */
2636 SetLastError(0xdeadbeef);
2637 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2638 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2640 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2641 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2644 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2646 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2647 return TRUE;
2650 static void test_EnumSystemLocalesEx(void)
2652 BOOL ret;
2654 if (!pEnumSystemLocalesEx)
2656 win_skip( "EnumSystemLocalesEx not available\n" );
2657 return;
2659 SetLastError( 0xdeadbeef );
2660 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2661 ok( !ret, "should have failed\n" );
2662 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2663 SetLastError( 0xdeadbeef );
2664 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2665 ok( ret, "failed err %u\n", GetLastError() );
2668 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2669 LONG_PTR lParam)
2671 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2673 /* invalid locale enumerated on some platforms */
2674 if (lcid == 0)
2675 return TRUE;
2677 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2678 "Enumerated grp %d not valid\n", lgrpid);
2679 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2680 "Enumerated grp locale %d not valid\n", lcid);
2681 return TRUE;
2684 static void test_EnumLanguageGroupLocalesA(void)
2686 BOOL ret;
2688 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2690 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2691 return;
2694 /* No enumeration proc */
2695 SetLastError(0);
2696 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2697 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2699 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2700 return;
2702 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2703 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2705 /* lgrpid too small */
2706 SetLastError(0);
2707 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2708 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2709 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2711 /* lgrpid too big */
2712 SetLastError(0);
2713 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2714 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2715 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2717 /* dwFlags is reserved */
2718 SetLastError(0);
2719 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2720 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2721 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2723 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2726 static void test_SetLocaleInfoA(void)
2728 BOOL bRet;
2729 LCID lcid = GetUserDefaultLCID();
2731 /* Null data */
2732 SetLastError(0);
2733 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2734 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2735 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2737 /* IDATE */
2738 SetLastError(0);
2739 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2740 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2741 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2743 /* ILDATE */
2744 SetLastError(0);
2745 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2746 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2747 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2750 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2752 trace("%s %08lx\n", value, lParam);
2753 return(TRUE);
2756 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2758 ok(!enumCount, "callback called again unexpected\n");
2759 enumCount++;
2760 return(FALSE);
2763 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2765 ok(0,"callback called unexpected\n");
2766 return(FALSE);
2769 static void test_EnumUILanguageA(void)
2771 BOOL ret;
2772 if (!pEnumUILanguagesA) {
2773 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2774 return;
2777 SetLastError(ERROR_SUCCESS);
2778 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2779 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2781 win_skip("EnumUILanguagesA is not implemented\n");
2782 return;
2784 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2786 enumCount = 0;
2787 SetLastError(ERROR_SUCCESS);
2788 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2789 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2791 SetLastError(ERROR_SUCCESS);
2792 ret = pEnumUILanguagesA(NULL, 0, 0);
2793 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2794 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2795 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2797 SetLastError(ERROR_SUCCESS);
2798 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2799 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2800 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2802 SetLastError(ERROR_SUCCESS);
2803 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2804 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2805 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2806 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2809 static char date_fmt_buf[1024];
2811 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2813 lstrcatA(date_fmt_buf, fmt);
2814 lstrcatA(date_fmt_buf, "\n");
2815 return TRUE;
2818 static void test_EnumDateFormatsA(void)
2820 char *p, buf[256];
2821 BOOL ret;
2822 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2824 trace("EnumDateFormatsA 0\n");
2825 date_fmt_buf[0] = 0;
2826 SetLastError(0xdeadbeef);
2827 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2828 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2830 win_skip("0 for dwFlags is not supported\n");
2832 else
2834 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2835 trace("%s\n", date_fmt_buf);
2836 /* test the 1st enumerated format */
2837 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2838 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2839 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2840 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2843 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2844 date_fmt_buf[0] = 0;
2845 SetLastError(0xdeadbeef);
2846 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2847 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2849 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2851 else
2853 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2854 trace("%s\n", date_fmt_buf);
2855 /* test the 1st enumerated format */
2856 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2857 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2858 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2859 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2862 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2863 date_fmt_buf[0] = 0;
2864 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2865 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2866 trace("%s\n", date_fmt_buf);
2867 /* test the 1st enumerated format */
2868 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2869 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2870 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2871 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2873 trace("EnumDateFormatsA DATE_LONGDATE\n");
2874 date_fmt_buf[0] = 0;
2875 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2876 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2877 trace("%s\n", date_fmt_buf);
2878 /* test the 1st enumerated format */
2879 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2880 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2881 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2882 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2884 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2885 date_fmt_buf[0] = 0;
2886 SetLastError(0xdeadbeef);
2887 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2888 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2890 skip("DATE_YEARMONTH is only present on W2K and later\n");
2891 return;
2893 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2894 trace("%s\n", date_fmt_buf);
2895 /* test the 1st enumerated format */
2896 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2897 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2898 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2899 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2900 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2903 static void test_EnumTimeFormatsA(void)
2905 char *p, buf[256];
2906 BOOL ret;
2907 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2909 trace("EnumTimeFormatsA 0\n");
2910 date_fmt_buf[0] = 0;
2911 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2912 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2913 trace("%s\n", date_fmt_buf);
2914 /* test the 1st enumerated format */
2915 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2916 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2917 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2918 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2920 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2921 date_fmt_buf[0] = 0;
2922 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2923 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2924 trace("%s\n", date_fmt_buf);
2925 /* test the 1st enumerated format */
2926 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2927 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2928 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2929 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2932 static void test_GetCPInfo(void)
2934 BOOL ret;
2935 CPINFO cpinfo;
2937 SetLastError(0xdeadbeef);
2938 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2939 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2940 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2941 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2943 SetLastError(0xdeadbeef);
2944 ret = GetCPInfo(CP_UTF7, &cpinfo);
2945 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2947 skip("Codepage CP_UTF7 is not installed/available\n");
2949 else
2951 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2952 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2953 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2954 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2955 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2956 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2959 SetLastError(0xdeadbeef);
2960 ret = GetCPInfo(CP_UTF8, &cpinfo);
2961 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2963 skip("Codepage CP_UTF8 is not installed/available\n");
2965 else
2967 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2968 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2969 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2970 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2971 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2972 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2973 "expected 4, got %u\n", cpinfo.MaxCharSize);
2978 * The CT_TYPE1 has varied over windows version.
2979 * The current target for correct behavior is windows 7.
2980 * There was a big shift between windows 2000 (first introduced) and windows Xp
2981 * Most of the old values below are from windows 2000.
2982 * A smaller subset of changes happened between windows Xp and Window vista/7
2984 static void test_GetStringTypeW(void)
2986 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2987 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2988 C1_SPACE | C1_BLANK | C1_DEFINED,
2989 C1_SPACE | C1_BLANK | C1_DEFINED,
2990 C1_SPACE | C1_BLANK | C1_DEFINED,
2991 C1_CNTRL | C1_BLANK | C1_DEFINED};
2992 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2993 C1_SPACE | C1_BLANK,
2994 C1_SPACE | C1_BLANK,
2995 C1_SPACE | C1_BLANK,
2996 C1_SPACE | C1_BLANK};
2998 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
3000 /* Lu, Ll, Lt */
3001 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3002 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3003 C1_LOWER | C1_ALPHA,
3004 C1_UPPER | C1_LOWER | C1_ALPHA,
3005 C1_ALPHA};
3007 /* Sk, Sk, Mn, So, Me */
3008 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3009 /* Sc, Sm, No,*/
3010 0xffe0, 0xffe9, 0x2153};
3012 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3013 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3014 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3015 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3016 C1_ALPHA | C1_DEFINED,
3017 C1_CNTRL | C1_DEFINED,
3018 C1_PUNCT | C1_DEFINED,
3019 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3020 C1_ALPHA | C1_LOWER | C1_DEFINED,
3021 C1_ALPHA | C1_DEFINED };
3022 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3023 C1_ALPHA | C1_DEFINED,
3024 C1_CNTRL | C1_DEFINED,
3025 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3026 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3027 C1_ALPHA | C1_DEFINED,
3028 C1_DEFINED
3030 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3031 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3033 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3034 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3035 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3036 static const WCHAR lower_special[] = {0x2071, 0x207f};
3037 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3038 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3039 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3040 0xfff9, 0xfffa, 0xfffb};
3041 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3043 WORD types[20];
3044 int i;
3046 memset(types,0,sizeof(types));
3047 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3048 for (i = 0; i < 5; i++)
3049 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]);
3051 memset(types,0,sizeof(types));
3052 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3053 for (i = 0; i < 3; i++)
3054 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]));
3055 memset(types,0,sizeof(types));
3056 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3057 for (i = 0; i < 5; i++)
3058 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3060 memset(types,0,sizeof(types));
3061 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3062 for (i = 0; i < 8; i++)
3063 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);
3065 memset(types,0,sizeof(types));
3066 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3067 for (i = 0; i < 7; i++)
3068 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]);
3070 memset(types,0,sizeof(types));
3071 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3072 for (i = 0; i < 7; i++)
3073 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));
3076 memset(types,0,sizeof(types));
3077 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3078 for (i = 0; i < 12; i++)
3079 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);
3081 memset(types,0,sizeof(types));
3082 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3083 for (i = 0; i < 3; i++)
3084 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);
3086 memset(types,0,sizeof(types));
3087 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3088 for (i = 0; i < 2; i++)
3089 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);
3091 memset(types,0,sizeof(types));
3092 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3093 for (i = 0; i < 20; i++)
3094 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);
3096 memset(types,0,sizeof(types));
3097 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3098 for (i = 0; i < 3; i++)
3099 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 );
3102 static void test_IdnToNameprepUnicode(void)
3104 struct {
3105 DWORD in_len;
3106 const WCHAR in[64];
3107 DWORD ret;
3108 const WCHAR out[64];
3109 DWORD flags;
3110 DWORD err;
3111 DWORD todo;
3112 } test_data[] = {
3114 5, {'t','e','s','t',0},
3115 5, {'t','e','s','t',0},
3116 0, 0xdeadbeef
3119 3, {'a',0xe111,'b'},
3120 0, {0},
3121 0, ERROR_INVALID_NAME
3124 4, {'t',0,'e',0},
3125 0, {0},
3126 0, ERROR_INVALID_NAME
3129 1, {'T',0},
3130 1, {'T',0},
3131 0, 0xdeadbeef
3134 1, {0},
3135 0, {0},
3136 0, ERROR_INVALID_NAME
3139 6, {' ','-','/','[',']',0},
3140 6, {' ','-','/','[',']',0},
3141 0, 0xdeadbeef
3144 3, {'a','-','a'},
3145 3, {'a','-','a'},
3146 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3149 3, {'a','a','-'},
3150 0, {0},
3151 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3153 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3154 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3155 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3156 0, 0xdeadbeef, TRUE
3159 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3160 2, {'t',0},
3161 0, 0xdeadbeef
3163 { /* Another example of incorrectly working FoldString (composition) */
3164 2, {0x3b0, 0},
3165 2, {0x3b0, 0},
3166 0, 0xdeadbeef, TRUE
3169 2, {0x221, 0},
3170 0, {0},
3171 0, ERROR_NO_UNICODE_TRANSLATION
3174 2, {0x221, 0},
3175 2, {0x221, 0},
3176 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3179 5, {'a','.','.','a',0},
3180 0, {0},
3181 0, ERROR_INVALID_NAME
3184 3, {'a','.',0},
3185 3, {'a','.',0},
3186 0, 0xdeadbeef
3190 WCHAR buf[1024];
3191 DWORD i, ret, err;
3193 if (!pIdnToNameprepUnicode)
3195 win_skip("IdnToNameprepUnicode is not available\n");
3196 return;
3199 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3200 test_data[0].in_len, NULL, 0);
3201 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3203 SetLastError(0xdeadbeef);
3204 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3205 test_data[1].in_len, NULL, 0);
3206 err = GetLastError();
3207 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3208 ok(err == test_data[1].err, "err = %d\n", err);
3210 SetLastError(0xdeadbeef);
3211 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3212 buf, sizeof(buf)/sizeof(WCHAR));
3213 err = GetLastError();
3214 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3215 ok(err == 0xdeadbeef, "err = %d\n", err);
3217 SetLastError(0xdeadbeef);
3218 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3219 buf, sizeof(buf)/sizeof(WCHAR));
3220 err = GetLastError();
3221 ok(ret == 0, "ret = %d\n", ret);
3222 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3224 SetLastError(0xdeadbeef);
3225 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3226 buf, sizeof(buf)/sizeof(WCHAR));
3227 err = GetLastError();
3228 ok(ret == 0, "ret = %d\n", ret);
3229 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3231 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3232 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3233 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3235 SetLastError(0xdeadbeef);
3236 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3237 err = GetLastError();
3238 ok(ret == 0, "ret = %d\n", ret);
3239 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3241 SetLastError(0xdeadbeef);
3242 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3243 err = GetLastError();
3244 ok(ret == 0, "ret = %d\n", ret);
3245 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3247 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3249 SetLastError(0xdeadbeef);
3250 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3251 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3252 err = GetLastError();
3253 if(!test_data[i].todo) {
3254 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3255 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3256 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3257 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3258 }else {
3259 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3260 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3265 static void test_IdnToAscii(void)
3267 struct {
3268 DWORD in_len;
3269 const WCHAR in[64];
3270 DWORD ret;
3271 const WCHAR out[64];
3272 DWORD flags;
3273 DWORD err;
3274 } test_data[] = {
3276 5, {'T','e','s','t',0},
3277 5, {'T','e','s','t',0},
3278 0, 0xdeadbeef
3281 5, {'T','e',0x017c,'s','t',0},
3282 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3283 0, 0xdeadbeef
3286 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3287 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3288 0, 0xdeadbeef
3291 3, {0x0105,'.',0},
3292 9, {'x','n','-','-','2','d','a','.',0},
3293 0, 0xdeadbeef
3296 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3297 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3298 0, 0xdeadbeef
3301 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3302 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3303 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3304 0, 0xdeadbeef
3307 2, {0x221,0},
3308 8, {'x','n','-','-','6','l','a',0},
3309 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3313 WCHAR buf[1024];
3314 DWORD i, ret, err;
3316 if (!pIdnToAscii)
3318 win_skip("IdnToAscii is not available\n");
3319 return;
3322 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3324 SetLastError(0xdeadbeef);
3325 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3326 test_data[i].in_len, buf, sizeof(buf));
3327 err = GetLastError();
3328 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3329 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3330 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3331 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3335 static void test_IdnToUnicode(void)
3337 struct {
3338 DWORD in_len;
3339 const WCHAR in[64];
3340 DWORD ret;
3341 const WCHAR out[64];
3342 DWORD flags;
3343 DWORD err;
3344 } test_data[] = {
3346 5, {'T','e','s','.',0},
3347 5, {'T','e','s','.',0},
3348 0, 0xdeadbeef
3351 2, {0x105,0},
3352 0, {0},
3353 0, ERROR_INVALID_NAME
3356 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3357 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3358 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3359 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3360 0x05d1,0x05e8,0x05d9,0x05ea,0},
3361 0, 0xdeadbeef
3364 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3365 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3366 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3367 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3368 0, 0xdeadbeef
3371 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3372 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3373 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3374 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3375 0, {0},
3376 0, ERROR_INVALID_NAME
3379 8, {'x','n','-','-','6','l','a',0},
3380 2, {0x221,0},
3381 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3385 WCHAR buf[1024];
3386 DWORD i, ret, err;
3388 if (!pIdnToUnicode)
3390 win_skip("IdnToUnicode is not available\n");
3391 return;
3394 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3396 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3397 test_data[i].in_len, NULL, 0);
3398 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3400 SetLastError(0xdeadbeef);
3401 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3402 test_data[i].in_len, buf, sizeof(buf));
3403 err = GetLastError();
3404 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3405 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3406 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3407 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3411 static void test_GetLocaleInfoEx(void)
3413 static const WCHAR enW[] = {'e','n',0};
3414 WCHAR bufferW[80];
3415 INT ret;
3417 if (!pGetLocaleInfoEx)
3419 win_skip("GetLocaleInfoEx not supported\n");
3420 return;
3423 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3424 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3425 if (ret)
3427 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3428 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3429 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3430 static const WCHAR usaW[] = {'U','S','A',0};
3431 static const WCHAR enuW[] = {'E','N','U',0};
3432 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3433 DWORD val;
3435 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3436 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3438 SetLastError(0xdeadbeef);
3439 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
3440 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
3442 SetLastError(0xdeadbeef);
3443 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
3444 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
3446 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3447 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3448 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3450 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3451 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3452 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3454 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3455 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3456 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3458 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3459 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
3460 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
3461 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
3463 skip("Non-English locale\n");
3465 else
3466 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3468 bufferW[0] = 0;
3469 SetLastError(0xdeadbeef);
3470 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3471 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
3473 while (*ptr->name)
3475 val = 0;
3476 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3477 if (ptr->todo)
3478 todo_wine
3479 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3480 else
3481 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3482 bufferW[0] = 0;
3483 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3484 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
3485 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
3486 ptr++;
3491 static void test_IsValidLocaleName(void)
3493 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3494 static const WCHAR zzW[] = {'z','z',0};
3495 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
3496 BOOL ret;
3498 if (!pIsValidLocaleName)
3500 win_skip("IsValidLocaleName not supported\n");
3501 return;
3504 ret = pIsValidLocaleName(enusW);
3505 ok(ret, "IsValidLocaleName failed\n");
3506 ret = pIsValidLocaleName(zzW);
3507 ok(!ret, "IsValidLocaleName should have failed\n");
3508 ret = pIsValidLocaleName(zzzzW);
3509 ok(!ret, "IsValidLocaleName should have failed\n");
3512 static void test_CompareStringOrdinal(void)
3514 INT ret;
3515 WCHAR test1[] = { 't','e','s','t',0 };
3516 WCHAR test2[] = { 'T','e','S','t',0 };
3517 WCHAR test3[] = { 't','e','s','t','3',0 };
3518 WCHAR null1[] = { 'a',0,'a',0 };
3519 WCHAR null2[] = { 'a',0,'b',0 };
3520 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
3521 WCHAR bills2[] = { 'b','i','l','l','s',0 };
3522 WCHAR coop1[] = { 'c','o','-','o','p',0 };
3523 WCHAR coop2[] = { 'c','o','o','p',0 };
3524 WCHAR nonascii1[] = { 0x0102,0 };
3525 WCHAR nonascii2[] = { 0x0201,0 };
3527 if (!pCompareStringOrdinal)
3529 win_skip("CompareStringOrdinal not supported\n");
3530 return;
3533 /* Check errors */
3534 SetLastError(0xdeadbeef);
3535 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
3536 ok(!ret, "Got %u, expected 0\n", ret);
3537 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3538 SetLastError(0xdeadbeef);
3539 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
3540 ok(!ret, "Got %u, expected 0\n", ret);
3541 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3542 SetLastError(0xdeadbeef);
3543 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
3544 ok(!ret, "Got %u, expected 0\n", ret);
3545 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
3547 /* Check case */
3548 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
3549 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3550 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
3551 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3552 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
3553 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3554 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
3555 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
3557 /* Check different sizes */
3558 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
3559 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3560 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
3561 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3563 /* Check null character */
3564 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
3565 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3566 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
3567 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3568 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
3569 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3570 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
3571 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3573 /* Check ordinal behaviour */
3574 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
3575 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3576 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
3577 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
3578 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
3579 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3580 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
3581 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
3584 START_TEST(locale)
3586 InitFunctionPointers();
3588 test_EnumTimeFormatsA();
3589 test_EnumDateFormatsA();
3590 test_GetLocaleInfoA();
3591 test_GetLocaleInfoW();
3592 test_GetLocaleInfoEx();
3593 test_GetTimeFormatA();
3594 test_GetDateFormatA();
3595 test_GetDateFormatW();
3596 test_GetCurrencyFormatA(); /* Also tests the W version */
3597 test_GetNumberFormatA(); /* Also tests the W version */
3598 test_CompareStringA();
3599 test_LCMapStringA();
3600 test_LCMapStringW();
3601 test_LCMapStringEx();
3602 test_LocaleNameToLCID();
3603 test_FoldStringA();
3604 test_FoldStringW();
3605 test_ConvertDefaultLocale();
3606 test_EnumSystemLanguageGroupsA();
3607 test_EnumSystemLocalesEx();
3608 test_EnumLanguageGroupLocalesA();
3609 test_SetLocaleInfoA();
3610 test_EnumUILanguageA();
3611 test_GetCPInfo();
3612 test_GetStringTypeW();
3613 test_IdnToNameprepUnicode();
3614 test_IdnToAscii();
3615 test_IdnToUnicode();
3616 test_IsValidLocaleName();
3617 test_CompareStringOrdinal();
3618 /* this requires collation table patch to make it MS compatible */
3619 if (0) test_sorting();