kernel32: Some test for handling locales specified by language only.
[wine/multimedia.git] / dlls / kernel32 / tests / locale.c
blob856b46eea62aa92c2288ef2b3e19c7ac9614955b
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);
90 static void InitFunctionPointers(void)
92 hKernel32 = GetModuleHandleA("kernel32");
93 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
94 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
95 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
96 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
97 pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
98 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
99 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
100 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
101 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
102 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
103 pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
104 pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
105 pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
106 pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
109 #define eq(received, expected, label, type) \
110 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
111 (label), (received), (expected))
113 #define BUFFER_SIZE 128
114 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
116 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
117 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
118 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
119 "Expected '%s', got '%s'\n", Expected, buffer)
121 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
122 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
123 SetLastError(0xdeadbeef); buffer[0] = '\0'
124 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
125 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
127 #define NUO LOCALE_NOUSEROVERRIDE
129 static void test_GetLocaleInfoA(void)
131 int ret;
132 int len;
133 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
134 char buffer[BUFFER_SIZE];
135 char expected[BUFFER_SIZE];
136 DWORD val;
138 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
140 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
141 ok(ret, "got %d\n", ret);
142 todo_wine
143 ok(val == lcid, "got 0x%08x\n", val);
145 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
146 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
147 assumes SUBLANG_NEUTRAL for zh */
148 memset(expected, 0, COUNTOF(expected));
149 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
150 SetLastError(0xdeadbeef);
151 memset(buffer, 0, COUNTOF(buffer));
152 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
153 ok((ret == len) && !lstrcmpA(buffer, expected),
154 "got %d with '%s' (expected %d with '%s')\n",
155 ret, buffer, len, expected);
157 memset(expected, 0, COUNTOF(expected));
158 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
159 if (len) {
160 SetLastError(0xdeadbeef);
161 memset(buffer, 0, COUNTOF(buffer));
162 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
163 ok((ret == len) && !lstrcmpA(buffer, expected),
164 "got %d with '%s' (expected %d with '%s')\n",
165 ret, buffer, len, expected);
167 else
168 win_skip("LANG_ARABIC not installed\n");
170 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
171 memset(expected, 0, COUNTOF(expected));
172 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
173 SetLastError(0xdeadbeef);
174 memset(buffer, 0, COUNTOF(buffer));
175 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
176 ok((ret == len) && !lstrcmpA(buffer, expected),
177 "got %d with '%s' (expected %d with '%s')\n",
178 ret, buffer, len, expected);
181 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
182 * partially fill the buffer even if it is too short. See bug 637.
184 SetLastError(0xdeadbeef);
185 memset(buffer, 0, COUNTOF(buffer));
186 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
187 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
189 SetLastError(0xdeadbeef);
190 memset(buffer, 0, COUNTOF(buffer));
191 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
192 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
193 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
194 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
196 SetLastError(0xdeadbeef);
197 memset(buffer, 0, COUNTOF(buffer));
198 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
199 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
200 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
203 struct neutralsublang_name2_t {
204 WCHAR name[3];
205 LCID lcid;
206 LCID lcid_broken;
209 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
210 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
211 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
212 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
213 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
214 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
215 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */ },
216 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
217 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
218 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
219 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
220 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
221 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
222 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
223 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
224 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
225 { {0} }
228 static void test_GetLocaleInfoW(void)
230 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
231 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
232 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
233 WCHAR bufferW[80], buffer2W[80];
234 CHAR bufferA[80];
235 DWORD val;
236 DWORD ret;
237 INT i;
239 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
240 if (!ret) {
241 win_skip("GetLocaleInfoW() isn't implemented\n");
242 return;
245 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
246 ok(ret, "got %d\n", ret);
247 todo_wine
248 ok(val == lcid_en, "got 0x%08x\n", val);
250 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
251 if (ret)
253 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
254 'S','t','a','t','e','s',')',0};
255 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
256 static const WCHAR enW[] = {'e','n','-','U','S',0};
257 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
259 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
261 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
262 ok(ret, "got %d\n", ret);
263 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
265 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
266 ok(ret, "got %d\n", ret);
267 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
269 while (*ptr->name)
271 LANGID langid;
273 /* make neutral lcid */
274 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
276 val = 0;
277 GetLocaleInfoW(MAKELCID(langid, SORT_DEFAULT), LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
278 todo_wine
279 ok(val == ptr->lcid || broken(val == ptr->lcid_broken), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
280 wine_dbgstr_w(ptr->name), val, ptr->lcid);
281 ptr++;
284 else
285 win_skip("English neutral locale not supported\n");
287 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
288 if (!ret) {
289 win_skip("LANG_RUSSIAN locale data unavailable\n");
290 return;
292 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
293 bufferW, COUNTOF(bufferW));
294 if (!ret) {
295 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
296 return;
299 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
300 bufferA[0] = 'a';
301 SetLastError(0xdeadbeef);
302 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
303 bufferA, COUNTOF(bufferA));
304 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
305 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
306 ok(GetLastError() == ERROR_INVALID_FLAGS,
307 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
309 bufferW[0] = 'a';
310 SetLastError(0xdeadbeef);
311 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
312 bufferW, COUNTOF(bufferW));
313 ok(ret == 0,
314 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
315 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
316 ok(GetLastError() == ERROR_INVALID_FLAGS,
317 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
319 /* yes, test empty 13 month entry too */
320 for (i = 0; i < 12; i++) {
321 bufferW[0] = 0;
322 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
323 bufferW, COUNTOF(bufferW));
324 ok(ret, "Expected non zero result\n");
325 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
326 ret, lstrlenW(bufferW));
327 buffer2W[0] = 0;
328 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
329 buffer2W, COUNTOF(buffer2W));
330 ok(ret, "Expected non zero result\n");
331 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
332 ret, lstrlenW(buffer2W));
334 ok(lstrcmpW(bufferW, buffer2W) != 0,
335 "Expected genitive name to differ, got the same for month %d\n", i+1);
337 /* for locale without genitive names nominative returned in both cases */
338 bufferW[0] = 0;
339 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
340 bufferW, COUNTOF(bufferW));
341 ok(ret, "Expected non zero result\n");
342 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
343 ret, lstrlenW(bufferW));
344 buffer2W[0] = 0;
345 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
346 buffer2W, COUNTOF(buffer2W));
347 ok(ret, "Expected non zero result\n");
348 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
349 ret, lstrlenW(buffer2W));
351 ok(lstrcmpW(bufferW, buffer2W) == 0,
352 "Expected same names, got different for month %d\n", i+1);
356 static void test_GetTimeFormatA(void)
358 int ret;
359 SYSTEMTIME curtime;
360 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
361 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
363 memset(&curtime, 2, sizeof(SYSTEMTIME));
364 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
365 SetLastError(0xdeadbeef);
366 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
367 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
368 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
370 curtime.wHour = 8;
371 curtime.wMinute = 56;
372 curtime.wSecond = 13;
373 curtime.wMilliseconds = 22;
374 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
375 SetLastError(0xdeadbeef);
376 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
377 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
378 EXPECT_LENA; EXPECT_EQA;
380 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
381 SetLastError(0xdeadbeef);
382 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
383 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
384 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
386 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
387 SetLastError(0xdeadbeef);
388 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
389 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
390 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
392 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
393 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
394 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
395 EXPECT_LENA;
397 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
398 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
399 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
400 EXPECT_LENA; EXPECT_EQA;
402 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
403 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
404 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
405 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
406 "Expected '', got '%s'\n", buffer );
408 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
409 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
410 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
411 EXPECT_LENA; EXPECT_EQA;
413 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
414 strcpy(Expected, "8:56 AM");
415 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
416 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
417 EXPECT_LENA; EXPECT_EQA;
419 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
420 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
421 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
422 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
423 "Expected '8.@:56AM', got '%s'\n", buffer );
425 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
426 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
427 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
428 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
429 "Expected '', got '%s'\n", buffer );
431 STRINGSA("t/tt", "A/AM"); /* AM time marker */
432 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
433 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
434 EXPECT_LENA; EXPECT_EQA;
436 curtime.wHour = 13;
437 STRINGSA("t/tt", "P/PM"); /* PM time marker */
438 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
439 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
440 EXPECT_LENA; EXPECT_EQA;
442 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
443 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
444 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
445 EXPECT_LENA; EXPECT_EQA;
447 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
448 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
450 EXPECT_LENA; EXPECT_EQA;
452 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
453 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
454 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
455 EXPECT_LENA; EXPECT_EQA;
457 curtime.wHour = 14; /* change this to 14 or 2pm */
458 curtime.wMinute = 5;
459 curtime.wSecond = 3;
460 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 */
461 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
462 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
463 EXPECT_LENA; EXPECT_EQA;
465 curtime.wHour = 0;
466 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
467 ret = GetTimeFormatA(lcid, 0, &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", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
472 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
473 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
474 EXPECT_LENA; EXPECT_EQA;
476 /* try to convert formatting strings with more than two letters
477 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
478 * NOTE: We expect any letter for which there is an upper case value
479 * we should see a replacement. For letters that DO NOT have
480 * upper case values we should see NO REPLACEMENT.
482 curtime.wHour = 8;
483 curtime.wMinute = 56;
484 curtime.wSecond = 13;
485 curtime.wMilliseconds = 22;
486 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
487 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
488 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
489 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
490 EXPECT_LENA; EXPECT_EQA;
492 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
493 strcpy(buffer, "text");
494 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
495 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
496 EXPECT_EQA;
498 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
499 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
500 ret = GetTimeFormatA(lcid, 0, &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("'''", "'"); /* invalid quoted string */
505 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
506 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
507 EXPECT_LENA; EXPECT_EQA;
509 /* test that msdn suggested single quotation usage works as expected */
510 STRINGSA("''''", "'"); /* single quote mark */
511 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
512 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
513 EXPECT_LENA; EXPECT_EQA;
515 STRINGSA("''HHHHHH", "08"); /* Normal use */
516 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
517 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
518 EXPECT_LENA; EXPECT_EQA;
520 /* and test for normal use of the single quotation mark */
521 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
522 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
523 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
524 EXPECT_LENA; EXPECT_EQA;
526 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
527 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
528 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
529 EXPECT_LENA; EXPECT_EQA;
531 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
532 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
533 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
534 EXPECT_LENA; EXPECT_EQA;
536 curtime.wHour = 25;
537 STRINGSA("'123'tt", ""); /* Invalid time */
538 SetLastError(0xdeadbeef);
539 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
540 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
541 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
543 curtime.wHour = 12;
544 curtime.wMonth = 60; /* Invalid */
545 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
546 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
547 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
548 EXPECT_LENA; EXPECT_EQA;
551 static void test_GetDateFormatA(void)
553 int ret;
554 SYSTEMTIME curtime;
555 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
556 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
557 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
558 char Broken[BUFFER_SIZE];
559 char short_day[10], month[10], genitive_month[10];
561 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
562 STRINGSA("ddd',' MMM dd yy","");
563 SetLastError(0xdeadbeef);
564 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
565 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
566 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
568 curtime.wYear = 2002;
569 curtime.wMonth = 5;
570 curtime.wDay = 4;
571 curtime.wDayOfWeek = 3;
572 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
573 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
574 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
575 EXPECT_LENA; EXPECT_EQA;
577 /* Same as above but with LOCALE_NOUSEROVERRIDE */
578 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
579 SetLastError(0xdeadbeef);
580 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
581 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
582 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
583 EXPECT_EQA;
585 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
586 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
587 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
588 EXPECT_LENA; EXPECT_EQA;
590 curtime.wHour = 36; /* Invalid */
591 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
592 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
593 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
594 EXPECT_LENA; EXPECT_EQA;
596 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
597 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
598 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
599 EXPECT_EQA;
601 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
602 SetLastError(0xdeadbeef);
603 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
604 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
605 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
607 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
608 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
609 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
610 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
611 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
613 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
614 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
615 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
616 EXPECT_LENA; EXPECT_EQA;
618 /* test for expected DATE_YEARMONTH behavior with null format */
619 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
620 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
621 SetLastError(0xdeadbeef);
622 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
623 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
624 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
625 EXPECT_EQA;
627 /* Test that using invalid DATE_* flags results in the correct error */
628 /* and return values */
629 STRINGSA("m/d/y", ""); /* Invalid flags */
630 SetLastError(0xdeadbeef);
631 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
632 &curtime, input, buffer, COUNTOF(buffer));
633 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
634 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
636 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
637 if (!ret)
639 win_skip("LANG_RUSSIAN locale data unavailable\n");
640 return;
643 /* month part should be in genitive form */
644 strcpy(genitive_month, buffer + 2);
645 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
646 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
647 strcpy(month, buffer);
648 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
650 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
651 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
652 strcpy(short_day, buffer);
654 STRINGSA("dd MMMMddd dd", "");
655 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
656 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
657 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
658 EXPECT_EQA;
660 STRINGSA("MMMMddd dd", "");
661 sprintf(Expected, "%s%s 04", month, short_day);
662 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
663 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
664 EXPECT_EQA;
666 STRINGSA("MMMMddd", "");
667 sprintf(Expected, "%s%s", month, short_day);
668 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
669 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
670 EXPECT_EQA;
672 STRINGSA("MMMMdd", "");
673 sprintf(Expected, "%s04", genitive_month);
674 sprintf(Broken, "%s04", month);
675 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
676 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
677 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
678 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
679 "Expected '%s', got '%s'\n", Expected, buffer);
681 STRINGSA("MMMMdd ddd", "");
682 sprintf(Expected, "%s04 %s", genitive_month, short_day);
683 sprintf(Broken, "%s04 %s", month, short_day);
684 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
685 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
686 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
687 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
688 "Expected '%s', got '%s'\n", Expected, buffer);
690 STRINGSA("dd dddMMMM", "");
691 sprintf(Expected, "04 %s%s", short_day, month);
692 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
693 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
694 EXPECT_EQA;
696 STRINGSA("dd dddMMMM ddd MMMMdd", "");
697 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
698 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
699 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
700 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
701 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
702 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
703 "Expected '%s', got '%s'\n", Expected, buffer);
705 /* with literal part */
706 STRINGSA("ddd',' MMMM dd", "");
707 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
708 sprintf(Broken, "%s, %s 04", short_day, month);
709 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
710 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
711 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
712 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
713 "Expected '%s', got '%s'\n", Expected, buffer);
716 static void test_GetDateFormatW(void)
718 int ret;
719 SYSTEMTIME curtime;
720 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
721 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
723 STRINGSW("",""); /* If flags is not zero then format must be NULL */
724 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
725 input, buffer, COUNTOF(buffer));
726 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
728 win_skip("GetDateFormatW is not implemented\n");
729 return;
731 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
732 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
733 EXPECT_EQW;
735 STRINGSW("",""); /* NULL buffer, len > 0 */
736 SetLastError(0xdeadbeef);
737 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
738 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
739 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
741 STRINGSW("",""); /* NULL buffer, len == 0 */
742 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
743 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
744 EXPECT_LENW; EXPECT_EQW;
746 curtime.wYear = 2002;
747 curtime.wMonth = 10;
748 curtime.wDay = 23;
749 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
750 curtime.wHour = 65432; /* Invalid */
751 curtime.wMinute = 34512; /* Invalid */
752 curtime.wSecond = 65535; /* Invalid */
753 curtime.wMilliseconds = 12345;
754 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
755 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
757 EXPECT_LENW; EXPECT_EQW;
759 /* Limit tests */
761 curtime.wYear = 1601;
762 curtime.wMonth = 1;
763 curtime.wDay = 1;
764 curtime.wDayOfWeek = 0; /* Irrelevant */
765 curtime.wHour = 0;
766 curtime.wMinute = 0;
767 curtime.wSecond = 0;
768 curtime.wMilliseconds = 0;
769 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
770 SetLastError(0xdeadbeef);
771 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
772 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
773 EXPECT_LENW; EXPECT_EQW;
775 curtime.wYear = 1600;
776 curtime.wMonth = 12;
777 curtime.wDay = 31;
778 curtime.wDayOfWeek = 0; /* Irrelevant */
779 curtime.wHour = 23;
780 curtime.wMinute = 59;
781 curtime.wSecond = 59;
782 curtime.wMilliseconds = 999;
783 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
784 SetLastError(0xdeadbeef);
785 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
786 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
787 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
791 #define CY_POS_LEFT 0
792 #define CY_POS_RIGHT 1
793 #define CY_POS_LEFT_SPACE 2
794 #define CY_POS_RIGHT_SPACE 3
796 static void test_GetCurrencyFormatA(void)
798 static char szDot[] = { '.', '\0' };
799 static char szComma[] = { ',', '\0' };
800 static char szDollar[] = { '$', '\0' };
801 int ret;
802 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
803 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
804 CURRENCYFMTA format;
806 memset(&format, 0, sizeof(format));
808 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
809 SetLastError(0xdeadbeef);
810 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
811 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
812 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
814 STRINGSA("23,53",""); /* Invalid character --> Error */
815 SetLastError(0xdeadbeef);
816 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
817 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
818 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
820 STRINGSA("--",""); /* Double '-' --> Error */
821 SetLastError(0xdeadbeef);
822 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
823 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
824 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
826 STRINGSA("0-",""); /* Trailing '-' --> Error */
827 SetLastError(0xdeadbeef);
828 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
829 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
830 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
832 STRINGSA("0..",""); /* Double '.' --> Error */
833 SetLastError(0xdeadbeef);
834 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
835 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
836 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
838 STRINGSA(" 0.1",""); /* Leading space --> Error */
839 SetLastError(0xdeadbeef);
840 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
841 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
842 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
844 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
845 SetLastError(0xdeadbeef);
846 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
847 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
848 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
850 STRINGSA("2353",""); /* Format and flags given --> Error */
851 SetLastError(0xdeadbeef);
852 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
853 ok( !ret, "Expected ret == 0, got %d\n", ret);
854 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
855 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
857 STRINGSA("2353",""); /* Invalid format --> Error */
858 SetLastError(0xdeadbeef);
859 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
860 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
861 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
863 STRINGSA("2353","$2,353.00"); /* Valid number */
864 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
865 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
866 EXPECT_LENA; EXPECT_EQA;
868 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
869 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
870 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
871 EXPECT_LENA; EXPECT_EQA;
873 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
874 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
875 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
876 EXPECT_LENA; EXPECT_EQA;
878 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
879 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
880 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
881 EXPECT_LENA; EXPECT_EQA;
883 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
884 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
885 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
886 EXPECT_LENA; EXPECT_EQA;
888 format.NumDigits = 0; /* No decimal separator */
889 format.LeadingZero = 0;
890 format.Grouping = 0; /* No grouping char */
891 format.NegativeOrder = 0;
892 format.PositiveOrder = CY_POS_LEFT;
893 format.lpDecimalSep = szDot;
894 format.lpThousandSep = szComma;
895 format.lpCurrencySymbol = szDollar;
897 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
898 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
899 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
900 EXPECT_LENA; EXPECT_EQA;
902 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
903 STRINGSA("2353","$2353.0");
904 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
905 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
906 EXPECT_LENA; EXPECT_EQA;
908 format.Grouping = 2; /* Group by 100's */
909 STRINGSA("2353","$23,53.0");
910 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
911 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
912 EXPECT_LENA; EXPECT_EQA;
914 STRINGSA("235","$235.0"); /* Grouping of a positive number */
915 format.Grouping = 3;
916 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
917 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
918 EXPECT_LENA; EXPECT_EQA;
920 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
921 format.NegativeOrder = 2;
922 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
923 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
924 EXPECT_LENA; EXPECT_EQA;
926 format.LeadingZero = 1; /* Always provide leading zero */
927 STRINGSA(".5","$0.5");
928 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
929 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
930 EXPECT_LENA; EXPECT_EQA;
932 format.PositiveOrder = CY_POS_RIGHT;
933 STRINGSA("1","1.0$");
934 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
935 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
936 EXPECT_LENA; EXPECT_EQA;
938 format.PositiveOrder = CY_POS_LEFT_SPACE;
939 STRINGSA("1","$ 1.0");
940 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
941 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942 EXPECT_LENA; EXPECT_EQA;
944 format.PositiveOrder = CY_POS_RIGHT_SPACE;
945 STRINGSA("1","1.0 $");
946 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
947 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
948 EXPECT_LENA; EXPECT_EQA;
950 format.NegativeOrder = 0;
951 STRINGSA("-1","($1.0)");
952 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
953 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
954 EXPECT_LENA; EXPECT_EQA;
956 format.NegativeOrder = 1;
957 STRINGSA("-1","-$1.0");
958 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
959 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
960 EXPECT_LENA; EXPECT_EQA;
962 format.NegativeOrder = 2;
963 STRINGSA("-1","$-1.0");
964 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
965 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
966 EXPECT_LENA; EXPECT_EQA;
968 format.NegativeOrder = 3;
969 STRINGSA("-1","$1.0-");
970 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
971 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
972 EXPECT_LENA; EXPECT_EQA;
974 format.NegativeOrder = 4;
975 STRINGSA("-1","(1.0$)");
976 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
977 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
978 EXPECT_LENA; EXPECT_EQA;
980 format.NegativeOrder = 5;
981 STRINGSA("-1","-1.0$");
982 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
983 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
984 EXPECT_LENA; EXPECT_EQA;
986 format.NegativeOrder = 6;
987 STRINGSA("-1","1.0-$");
988 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
989 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
990 EXPECT_LENA; EXPECT_EQA;
992 format.NegativeOrder = 7;
993 STRINGSA("-1","1.0$-");
994 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
995 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
996 EXPECT_LENA; EXPECT_EQA;
998 format.NegativeOrder = 8;
999 STRINGSA("-1","-1.0 $");
1000 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1001 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1002 EXPECT_LENA; EXPECT_EQA;
1004 format.NegativeOrder = 9;
1005 STRINGSA("-1","-$ 1.0");
1006 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1007 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1008 EXPECT_LENA; EXPECT_EQA;
1010 format.NegativeOrder = 10;
1011 STRINGSA("-1","1.0 $-");
1012 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1013 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1014 EXPECT_LENA; EXPECT_EQA;
1016 format.NegativeOrder = 11;
1017 STRINGSA("-1","$ 1.0-");
1018 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1019 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1020 EXPECT_LENA; EXPECT_EQA;
1022 format.NegativeOrder = 12;
1023 STRINGSA("-1","$ -1.0");
1024 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1025 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1026 EXPECT_LENA; EXPECT_EQA;
1028 format.NegativeOrder = 13;
1029 STRINGSA("-1","1.0- $");
1030 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1031 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1032 EXPECT_LENA; EXPECT_EQA;
1034 format.NegativeOrder = 14;
1035 STRINGSA("-1","($ 1.0)");
1036 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1037 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1038 EXPECT_LENA; EXPECT_EQA;
1040 format.NegativeOrder = 15;
1041 STRINGSA("-1","(1.0 $)");
1042 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1043 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1044 EXPECT_LENA; EXPECT_EQA;
1047 #define NEG_PARENS 0 /* "(1.1)" */
1048 #define NEG_LEFT 1 /* "-1.1" */
1049 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1050 #define NEG_RIGHT 3 /* "1.1-" */
1051 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1053 static void test_GetNumberFormatA(void)
1055 static char szDot[] = { '.', '\0' };
1056 static char szComma[] = { ',', '\0' };
1057 int ret;
1058 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1059 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1060 NUMBERFMTA format;
1062 memset(&format, 0, sizeof(format));
1064 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1065 SetLastError(0xdeadbeef);
1066 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1067 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1068 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1070 STRINGSA("23,53",""); /* Invalid character --> Error */
1071 SetLastError(0xdeadbeef);
1072 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1073 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1074 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1076 STRINGSA("--",""); /* Double '-' --> Error */
1077 SetLastError(0xdeadbeef);
1078 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1079 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1080 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1082 STRINGSA("0-",""); /* Trailing '-' --> Error */
1083 SetLastError(0xdeadbeef);
1084 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1085 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1086 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1088 STRINGSA("0..",""); /* Double '.' --> Error */
1089 SetLastError(0xdeadbeef);
1090 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1091 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1092 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1094 STRINGSA(" 0.1",""); /* Leading space --> Error */
1095 SetLastError(0xdeadbeef);
1096 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1097 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1098 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1100 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1101 SetLastError(0xdeadbeef);
1102 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1103 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1104 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1106 STRINGSA("2353",""); /* Format and flags given --> Error */
1107 SetLastError(0xdeadbeef);
1108 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1109 ok( !ret, "Expected ret == 0, got %d\n", ret);
1110 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1111 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1113 STRINGSA("2353",""); /* Invalid format --> Error */
1114 SetLastError(0xdeadbeef);
1115 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1116 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1117 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1119 STRINGSA("2353","2,353.00"); /* Valid number */
1120 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1121 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1122 EXPECT_LENA; EXPECT_EQA;
1124 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1125 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1126 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1127 EXPECT_LENA; EXPECT_EQA;
1129 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1130 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1131 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1132 EXPECT_LENA; EXPECT_EQA;
1134 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1135 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1136 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1137 EXPECT_LENA; EXPECT_EQA;
1139 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1140 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1141 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1142 EXPECT_LENA; EXPECT_EQA;
1144 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1145 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1146 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1147 EXPECT_LENA; EXPECT_EQA;
1149 format.NumDigits = 0; /* No decimal separator */
1150 format.LeadingZero = 0;
1151 format.Grouping = 0; /* No grouping char */
1152 format.NegativeOrder = 0;
1153 format.lpDecimalSep = szDot;
1154 format.lpThousandSep = szComma;
1156 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1157 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1158 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1159 EXPECT_LENA; EXPECT_EQA;
1161 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1162 STRINGSA("2353","2353.0");
1163 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1164 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1165 EXPECT_LENA; EXPECT_EQA;
1167 format.Grouping = 2; /* Group by 100's */
1168 STRINGSA("2353","23,53.0");
1169 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1170 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1171 EXPECT_LENA; EXPECT_EQA;
1173 STRINGSA("235","235.0"); /* Grouping of a positive number */
1174 format.Grouping = 3;
1175 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1176 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1177 EXPECT_LENA; EXPECT_EQA;
1179 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1180 format.NegativeOrder = NEG_LEFT;
1181 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1182 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1183 EXPECT_LENA; EXPECT_EQA;
1185 format.LeadingZero = 1; /* Always provide leading zero */
1186 STRINGSA(".5","0.5");
1187 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1188 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1189 EXPECT_LENA; EXPECT_EQA;
1191 format.NegativeOrder = NEG_PARENS;
1192 STRINGSA("-1","(1.0)");
1193 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1194 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1195 EXPECT_LENA; EXPECT_EQA;
1197 format.NegativeOrder = NEG_LEFT;
1198 STRINGSA("-1","-1.0");
1199 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1200 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1201 EXPECT_LENA; EXPECT_EQA;
1203 format.NegativeOrder = NEG_LEFT_SPACE;
1204 STRINGSA("-1","- 1.0");
1205 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1206 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1207 EXPECT_LENA; EXPECT_EQA;
1209 format.NegativeOrder = NEG_RIGHT;
1210 STRINGSA("-1","1.0-");
1211 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1212 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1213 EXPECT_LENA; EXPECT_EQA;
1215 format.NegativeOrder = NEG_RIGHT_SPACE;
1216 STRINGSA("-1","1.0 -");
1217 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1218 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1219 EXPECT_LENA; EXPECT_EQA;
1221 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1223 if (IsValidLocale(lcid, 0))
1225 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1226 Expected[3] = 160; /* Non breaking space */
1227 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1228 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1229 EXPECT_LENA; EXPECT_EQA;
1233 struct comparestringa_entry {
1234 LCID lcid;
1235 DWORD flags;
1236 const char *first;
1237 int first_len;
1238 const char *second;
1239 int second_len;
1240 int ret;
1243 static const struct comparestringa_entry comparestringa_data[] = {
1244 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1245 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1246 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1247 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1248 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1249 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1250 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1251 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1252 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1253 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1254 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1255 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1256 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1257 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1258 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1259 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1260 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1261 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1262 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1263 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1264 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1265 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1266 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1267 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1268 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1269 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1270 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1271 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1272 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1273 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1276 static void test_CompareStringA(void)
1278 int ret, i;
1279 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1281 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1283 const struct comparestringa_entry *entry = &comparestringa_data[i];
1285 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1286 entry->second, entry->second_len);
1287 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1290 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1291 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1293 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1294 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1296 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1297 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1299 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1300 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1302 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1304 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1305 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1307 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1308 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1310 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1311 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1313 /* test for CompareStringA flags */
1314 SetLastError(0xdeadbeef);
1315 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1316 ok(GetLastError() == ERROR_INVALID_FLAGS,
1317 "unexpected error code %d\n", GetLastError());
1318 ok(!ret, "CompareStringA must fail with invalid flag\n");
1320 SetLastError(0xdeadbeef);
1321 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1322 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1323 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1324 /* end of test for CompareStringA flags */
1326 ret = lstrcmpA("", "");
1327 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1329 ret = lstrcmpA(NULL, NULL);
1330 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1332 ret = lstrcmpA("", NULL);
1333 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1335 ret = lstrcmpA(NULL, "");
1336 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1339 if (0) { /* this requires collation table patch to make it MS compatible */
1340 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1341 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1343 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1344 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1346 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1347 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1349 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1350 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1352 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1353 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1355 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1356 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1358 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1359 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1361 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1362 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1364 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1365 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1367 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1368 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1370 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1371 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1373 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1374 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1378 /* WinXP handles embedded NULLs differently than earlier versions */
1379 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1380 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1382 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1383 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);
1385 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1386 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1388 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1389 ok(ret == CSTR_EQUAL || /* win2k */
1390 ret == CSTR_GREATER_THAN,
1391 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1393 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1394 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1396 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1397 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1399 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1400 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1402 ret = lstrcmpi("#", ".");
1403 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1405 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1407 /* \xB9 character lies between a and b */
1408 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1409 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1410 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1411 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1414 static void test_LCMapStringA(void)
1416 int ret, ret2;
1417 char buf[256], buf2[256];
1418 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1419 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1420 static const char symbols_stripped[] = "justateststring1";
1422 SetLastError(0xdeadbeef);
1423 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1424 lower_case, -1, buf, sizeof(buf));
1425 ok(ret == lstrlenA(lower_case) + 1,
1426 "ret %d, error %d, expected value %d\n",
1427 ret, GetLastError(), lstrlenA(lower_case) + 1);
1428 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1430 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1431 upper_case, -1, buf, sizeof(buf));
1432 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1433 ok(GetLastError() == ERROR_INVALID_FLAGS,
1434 "unexpected error code %d\n", GetLastError());
1436 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1437 upper_case, -1, buf, sizeof(buf));
1438 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1439 ok(GetLastError() == ERROR_INVALID_FLAGS,
1440 "unexpected error code %d\n", GetLastError());
1442 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1443 upper_case, -1, buf, sizeof(buf));
1444 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1445 ok(GetLastError() == ERROR_INVALID_FLAGS,
1446 "unexpected error code %d\n", GetLastError());
1448 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1449 upper_case, -1, buf, sizeof(buf));
1450 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1451 ok(GetLastError() == ERROR_INVALID_FLAGS,
1452 "unexpected error code %d\n", GetLastError());
1454 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1455 SetLastError(0xdeadbeef);
1456 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1457 upper_case, -1, buf, sizeof(buf));
1458 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1459 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1461 /* test LCMAP_LOWERCASE */
1462 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1463 upper_case, -1, buf, sizeof(buf));
1464 ok(ret == lstrlenA(upper_case) + 1,
1465 "ret %d, error %d, expected value %d\n",
1466 ret, GetLastError(), lstrlenA(upper_case) + 1);
1467 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1469 /* test LCMAP_UPPERCASE */
1470 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1471 lower_case, -1, buf, sizeof(buf));
1472 ok(ret == lstrlenA(lower_case) + 1,
1473 "ret %d, error %d, expected value %d\n",
1474 ret, GetLastError(), lstrlenA(lower_case) + 1);
1475 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1477 /* test buffer overflow */
1478 SetLastError(0xdeadbeef);
1479 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1480 lower_case, -1, buf, 4);
1481 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1482 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1484 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1485 lstrcpyA(buf, lower_case);
1486 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1487 buf, -1, buf, sizeof(buf));
1488 if (!ret) /* Win9x */
1489 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1490 else
1492 ok(ret == lstrlenA(lower_case) + 1,
1493 "ret %d, error %d, expected value %d\n",
1494 ret, GetLastError(), lstrlenA(lower_case) + 1);
1495 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1497 lstrcpyA(buf, upper_case);
1498 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1499 buf, -1, buf, sizeof(buf));
1500 if (!ret) /* Win9x */
1501 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1502 else
1504 ok(ret == lstrlenA(upper_case) + 1,
1505 "ret %d, error %d, expected value %d\n",
1506 ret, GetLastError(), lstrlenA(lower_case) + 1);
1507 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1510 /* otherwise src == dst should fail */
1511 SetLastError(0xdeadbeef);
1512 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1513 buf, 10, buf, sizeof(buf));
1514 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1515 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1516 "unexpected error code %d\n", GetLastError());
1517 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1519 /* test whether '\0' is always appended */
1520 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1521 upper_case, -1, buf, sizeof(buf));
1522 ok(ret, "LCMapStringA must succeed\n");
1523 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1524 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1525 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1526 ok(ret2, "LCMapStringA must succeed\n");
1527 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1528 ok(ret == ret2, "lengths of sort keys must be equal\n");
1529 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1531 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1532 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1533 upper_case, -1, buf, sizeof(buf));
1534 ok(ret, "LCMapStringA must succeed\n");
1535 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1536 lower_case, -1, buf2, sizeof(buf2));
1537 ok(ret2, "LCMapStringA must succeed\n");
1538 ok(ret == ret2, "lengths of sort keys must be equal\n");
1539 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1541 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1542 results from plain LCMAP_SORTKEY on Vista */
1544 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1545 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1546 lower_case, -1, buf, sizeof(buf));
1547 ok(ret, "LCMapStringA must succeed\n");
1548 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1549 symbols_stripped, -1, buf2, sizeof(buf2));
1550 ok(ret2, "LCMapStringA must succeed\n");
1551 ok(ret == ret2, "lengths of sort keys must be equal\n");
1552 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1554 /* test NORM_IGNORENONSPACE */
1555 lstrcpyA(buf, "foo");
1556 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1557 lower_case, -1, buf, sizeof(buf));
1558 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1559 lstrlenA(lower_case) + 1, ret);
1560 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1562 /* test NORM_IGNORESYMBOLS */
1563 lstrcpyA(buf, "foo");
1564 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1565 lower_case, -1, buf, sizeof(buf));
1566 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1567 lstrlenA(symbols_stripped) + 1, ret);
1568 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1570 /* test srclen = 0 */
1571 SetLastError(0xdeadbeef);
1572 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1573 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1574 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1575 "unexpected error code %d\n", GetLastError());
1578 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1580 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1582 int ret, ret2;
1583 WCHAR buf[256], buf2[256];
1584 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1586 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1587 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1588 if (broken(ret))
1589 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1590 else
1592 ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1593 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1594 func_name, GetLastError());
1597 ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1598 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1599 ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1600 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1601 func_name, GetLastError());
1603 ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1604 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1605 ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1606 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1607 func_name, GetLastError());
1609 ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1610 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1611 ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1612 func_name);
1613 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1614 func_name, GetLastError());
1616 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1617 SetLastError(0xdeadbeef);
1618 ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1619 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1620 ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1621 func_name, GetLastError());
1622 ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1624 /* test LCMAP_LOWERCASE */
1625 ret = func_ptr(LCMAP_LOWERCASE,
1626 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1627 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1628 ret, GetLastError(), lstrlenW(upper_case) + 1);
1629 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1631 /* test LCMAP_UPPERCASE */
1632 ret = func_ptr(LCMAP_UPPERCASE,
1633 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1634 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1635 ret, GetLastError(), lstrlenW(lower_case) + 1);
1636 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1638 /* test buffer overflow */
1639 SetLastError(0xdeadbeef);
1640 ret = func_ptr(LCMAP_UPPERCASE,
1641 lower_case, -1, buf, 4);
1642 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1643 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1645 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1646 lstrcpyW(buf, lower_case);
1647 ret = func_ptr(LCMAP_UPPERCASE,
1648 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1649 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1650 ret, GetLastError(), lstrlenW(lower_case) + 1);
1651 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1653 lstrcpyW(buf, upper_case);
1654 ret = func_ptr(LCMAP_LOWERCASE,
1655 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1656 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1657 ret, GetLastError(), lstrlenW(lower_case) + 1);
1658 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1660 /* otherwise src == dst should fail */
1661 SetLastError(0xdeadbeef);
1662 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1663 buf, 10, buf, sizeof(buf));
1664 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1665 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1666 "%s unexpected error code %d\n", func_name, GetLastError());
1667 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1669 /* test whether '\0' is always appended */
1670 ret = func_ptr(LCMAP_SORTKEY,
1671 upper_case, -1, buf, sizeof(buf));
1672 ok(ret, "%s func_ptr must succeed\n", func_name);
1673 ret2 = func_ptr(LCMAP_SORTKEY,
1674 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1675 ok(ret, "%s func_ptr must succeed\n", func_name);
1676 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1677 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1679 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1680 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1681 upper_case, -1, buf, sizeof(buf));
1682 ok(ret, "%s func_ptr must succeed\n", func_name);
1683 ret2 = func_ptr(LCMAP_SORTKEY,
1684 lower_case, -1, buf2, sizeof(buf2));
1685 ok(ret2, "%s func_ptr must succeed\n", func_name);
1686 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1687 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1689 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1690 results from plain LCMAP_SORTKEY on Vista */
1692 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1693 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1694 lower_case, -1, buf, sizeof(buf));
1695 ok(ret, "%s func_ptr must succeed\n", func_name);
1696 ret2 = func_ptr(LCMAP_SORTKEY,
1697 symbols_stripped, -1, buf2, sizeof(buf2));
1698 ok(ret2, "%s func_ptr must succeed\n", func_name);
1699 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1700 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1702 /* test NORM_IGNORENONSPACE */
1703 lstrcpyW(buf, fooW);
1704 ret = func_ptr(NORM_IGNORENONSPACE,
1705 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1706 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1707 lstrlenW(lower_case) + 1, ret);
1708 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1710 /* test NORM_IGNORESYMBOLS */
1711 lstrcpyW(buf, fooW);
1712 ret = func_ptr(NORM_IGNORESYMBOLS,
1713 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1714 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1715 lstrlenW(symbols_stripped) + 1, ret);
1716 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1718 /* test srclen = 0 */
1719 SetLastError(0xdeadbeef);
1720 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1721 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1722 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1723 "%s unexpected error code %d\n", func_name, GetLastError());
1726 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1728 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1731 static void test_LCMapStringW(void)
1733 int ret;
1734 WCHAR buf[256];
1736 trace("testing LCMapStringW\n");
1738 SetLastError(0xdeadbeef);
1739 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1740 todo_wine {
1741 ok(!ret, "LCMapStringW should fail with bad lcid\n");
1742 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1745 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1748 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1750 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1753 static void test_LCMapStringEx(void)
1755 int ret;
1756 WCHAR buf[256], badname[] = {'w', 'i', 'n', 'e', 't', 'e', 's', 't', 0};
1758 if (!pLCMapStringEx)
1760 win_skip( "LCMapStringEx not available\n" );
1761 return;
1764 trace("testing LCMapStringEx\n");
1766 SetLastError(0xdeadbeef);
1767 ret = pLCMapStringEx(badname, LCMAP_LOWERCASE,
1768 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
1769 todo_wine {
1770 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
1771 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
1774 /* test reserved parameters */
1775 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1776 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1777 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1778 ret, GetLastError(), lstrlenW(upper_case) + 1);
1779 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1781 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1782 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1783 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1784 ret, GetLastError(), lstrlenW(upper_case) + 1);
1785 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1787 /* crashes on native */
1788 if(0)
1789 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1790 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1792 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1795 struct neutralsublang_name_t {
1796 WCHAR name[3];
1797 LCID lcid;
1798 int todo;
1801 static const struct neutralsublang_name_t neutralsublang_names[] = {
1802 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
1803 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
1804 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
1805 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
1806 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
1807 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 1 },
1808 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
1809 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
1810 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
1811 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
1812 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
1813 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
1814 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
1815 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
1816 { {0} }
1819 static void test_LocaleNameToLCID(void)
1821 LCID lcid;
1822 INT ret;
1823 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1824 static const WCHAR enW[] = {'e','n',0};
1826 if (!pLocaleNameToLCID)
1828 win_skip( "LocaleNameToLCID not available\n" );
1829 return;
1832 /* special cases */
1833 buffer[0] = 0;
1834 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1835 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1836 "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1837 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1838 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1839 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1841 buffer[0] = 0;
1842 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1843 todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1844 "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1845 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1846 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1847 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1849 buffer[0] = 0;
1850 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1851 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1852 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1853 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1854 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1856 /* english neutral name */
1857 lcid = pLocaleNameToLCID(enW, 0);
1858 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
1859 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
1860 if (lcid)
1862 const struct neutralsublang_name_t *ptr = neutralsublang_names;
1864 while (*ptr->name)
1866 lcid = pLocaleNameToLCID(ptr->name, 0);
1867 if (ptr->todo)
1868 todo_wine
1869 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1870 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1871 else
1872 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
1873 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
1874 ptr++;
1879 /* this requires collation table patch to make it MS compatible */
1880 static const char * const strings_sorted[] =
1882 "'",
1883 "-",
1884 "!",
1885 "\"",
1886 ".",
1887 ":",
1888 "\\",
1889 "_",
1890 "`",
1891 "{",
1892 "}",
1893 "+",
1894 "0",
1895 "1",
1896 "2",
1897 "3",
1898 "4",
1899 "5",
1900 "6",
1901 "7",
1902 "8",
1903 "9",
1904 "a",
1905 "A",
1906 "b",
1907 "B",
1908 "c",
1912 static const char * const strings[] =
1914 "C",
1915 "\"",
1916 "9",
1917 "'",
1918 "}",
1919 "-",
1920 "7",
1921 "+",
1922 "`",
1923 "1",
1924 "a",
1925 "5",
1926 "\\",
1927 "8",
1928 "B",
1929 "3",
1930 "_",
1931 "6",
1932 "{",
1933 "2",
1934 "c",
1935 "4",
1936 "!",
1937 "0",
1938 "A",
1939 ":",
1940 "b",
1944 static int compare_string1(const void *e1, const void *e2)
1946 const char *s1 = *(const char *const *)e1;
1947 const char *s2 = *(const char *const *)e2;
1949 return lstrcmpA(s1, s2);
1952 static int compare_string2(const void *e1, const void *e2)
1954 const char *s1 = *(const char *const *)e1;
1955 const char *s2 = *(const char *const *)e2;
1957 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1960 static int compare_string3(const void *e1, const void *e2)
1962 const char *s1 = *(const char *const *)e1;
1963 const char *s2 = *(const char *const *)e2;
1964 char key1[256], key2[256];
1966 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1967 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1968 return strcmp(key1, key2);
1971 static void test_sorting(void)
1973 char buf[256];
1974 char **str_buf = (char **)buf;
1975 int i;
1977 assert(sizeof(buf) >= sizeof(strings));
1979 /* 1. sort using lstrcmpA */
1980 memcpy(buf, strings, sizeof(strings));
1981 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1982 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1984 ok(!strcmp(strings_sorted[i], str_buf[i]),
1985 "qsort using lstrcmpA failed for element %d\n", i);
1987 /* 2. sort using CompareStringA */
1988 memcpy(buf, strings, sizeof(strings));
1989 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1990 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1992 ok(!strcmp(strings_sorted[i], str_buf[i]),
1993 "qsort using CompareStringA failed for element %d\n", i);
1995 /* 3. sort using sort keys */
1996 memcpy(buf, strings, sizeof(strings));
1997 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1998 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2000 ok(!strcmp(strings_sorted[i], str_buf[i]),
2001 "qsort using sort keys failed for element %d\n", i);
2005 static void test_FoldStringA(void)
2007 int ret, i, j;
2008 BOOL is_special;
2009 char src[256], dst[256];
2010 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2011 static const char digits_dst[] = { '1','2','3','\0' };
2012 static const char composite_src[] =
2014 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2015 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2016 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2017 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2018 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2019 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2020 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2021 0xfb,0xfc,0xfd,0xff,'\0'
2023 static const char composite_dst[] =
2025 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2026 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2027 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2028 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2029 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2030 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2031 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2032 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2033 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2034 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2035 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2036 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2037 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2038 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2039 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2041 static const char composite_dst_alt[] =
2043 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2044 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2045 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2046 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2047 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2048 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2049 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2050 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2051 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2052 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2053 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2054 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2055 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2056 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2057 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2059 static const char ligatures_src[] =
2061 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2063 static const char ligatures_dst[] =
2065 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2067 static const struct special
2069 char src;
2070 char dst[4];
2071 } foldczone_special[] =
2073 /* src dst */
2074 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2075 { 0x98, { 0x20, 0x7e, 0x00 } },
2076 { 0x99, { 0x54, 0x4d, 0x00 } },
2077 { 0xa0, { 0x20, 0x00 } },
2078 { 0xa8, { 0x20, 0xa8, 0x00 } },
2079 { 0xaa, { 0x61, 0x00 } },
2080 { 0xaf, { 0x20, 0xaf, 0x00 } },
2081 { 0xb2, { 0x32, 0x00 } },
2082 { 0xb3, { 0x33, 0x00 } },
2083 { 0xb4, { 0x20, 0xb4, 0x00 } },
2084 { 0xb8, { 0x20, 0xb8, 0x00 } },
2085 { 0xb9, { 0x31, 0x00 } },
2086 { 0xba, { 0x6f, 0x00 } },
2087 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2088 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2089 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2090 { 0x00 }
2093 if (!pFoldStringA)
2094 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2096 /* these tests are locale specific */
2097 if (GetACP() != 1252)
2099 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2100 return;
2103 /* MAP_FOLDDIGITS */
2104 SetLastError(0);
2105 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2106 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2108 win_skip("FoldStringA is not implemented\n");
2109 return;
2111 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2112 ok(strcmp(dst, digits_dst) == 0,
2113 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2114 for (i = 1; i < 256; i++)
2116 if (!strchr(digits_src, i))
2118 src[0] = i;
2119 src[1] = '\0';
2120 SetLastError(0);
2121 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2122 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2123 ok(dst[0] == src[0],
2124 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
2128 /* MAP_EXPAND_LIGATURES */
2129 SetLastError(0);
2130 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2131 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2132 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2133 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
2134 ok(strcmp(dst, ligatures_dst) == 0,
2135 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
2136 for (i = 1; i < 256; i++)
2138 if (!strchr(ligatures_src, i))
2140 src[0] = i;
2141 src[1] = '\0';
2142 SetLastError(0);
2143 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2144 if (ret == 3)
2146 /* Vista */
2147 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2148 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2149 "Got %s for %d\n", dst, i);
2151 else
2153 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2154 ok(dst[0] == src[0],
2155 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2161 /* MAP_COMPOSITE */
2162 SetLastError(0);
2163 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2164 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2165 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2166 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2167 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2169 for (i = 1; i < 256; i++)
2171 if (!strchr(composite_src, i))
2173 src[0] = i;
2174 src[1] = '\0';
2175 SetLastError(0);
2176 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2177 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2178 ok(dst[0] == src[0],
2179 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2180 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2184 /* MAP_FOLDCZONE */
2185 for (i = 1; i < 256; i++)
2187 src[0] = i;
2188 src[1] = '\0';
2189 SetLastError(0);
2190 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2191 is_special = FALSE;
2192 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2194 if (foldczone_special[j].src == src[0])
2196 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2197 "Expected ret == 2 or %d, got %d, error %d\n",
2198 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2199 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2200 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2201 (unsigned char)src[0]);
2202 is_special = TRUE;
2205 if (! is_special)
2207 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2208 ok(src[0] == dst[0],
2209 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2210 (unsigned char)src[0], (unsigned char)dst[0]);
2214 /* MAP_PRECOMPOSED */
2215 for (i = 1; i < 256; i++)
2217 src[0] = i;
2218 src[1] = '\0';
2219 SetLastError(0);
2220 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2221 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2222 ok(src[0] == dst[0],
2223 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2224 (unsigned char)src[0], (unsigned char)dst[0]);
2228 static void test_FoldStringW(void)
2230 int ret;
2231 unsigned int i, j;
2232 WCHAR src[256], dst[256], ch, prev_ch = 1;
2233 static const DWORD badFlags[] =
2236 MAP_PRECOMPOSED|MAP_COMPOSITE,
2237 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2238 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2240 /* Ranges of digits 0-9 : Must be sorted! */
2241 static const WCHAR digitRanges[] =
2243 0x0030, /* '0'-'9' */
2244 0x0660, /* Eastern Arabic */
2245 0x06F0, /* Arabic - Hindu */
2246 0x0966, /* Devengari */
2247 0x09E6, /* Bengalii */
2248 0x0A66, /* Gurmukhi */
2249 0x0AE6, /* Gujarati */
2250 0x0B66, /* Oriya */
2251 0x0BE6, /* Tamil - No 0 */
2252 0x0C66, /* Telugu */
2253 0x0CE6, /* Kannada */
2254 0x0D66, /* Maylayalam */
2255 0x0E50, /* Thai */
2256 0x0ED0, /* Laos */
2257 0x0F29, /* Tibet - 0 is out of sequence */
2258 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2259 0x2080, /* Subscript */
2260 0x245F, /* Circled - 0 is out of sequence */
2261 0x2473, /* Bracketed */
2262 0x2487, /* Full stop */
2263 0x2775, /* Inverted circled - No 0 */
2264 0x277F, /* Patterned circled - No 0 */
2265 0x2789, /* Inverted Patterned circled - No 0 */
2266 0x3020, /* Hangzhou */
2267 0xff10, /* Pliene chasse (?) */
2268 0xffff /* Terminator */
2270 /* Digits which are represented, but out of sequence */
2271 static const WCHAR outOfSequenceDigits[] =
2273 0xB9, /* Superscript 1 */
2274 0xB2, /* Superscript 2 */
2275 0xB3, /* Superscript 3 */
2276 0x0F33, /* Tibetan half zero */
2277 0x24EA, /* Circled 0 */
2278 0x3007, /* Ideographic number zero */
2279 '\0' /* Terminator */
2281 /* Digits in digitRanges for which no representation is available */
2282 static const WCHAR noDigitAvailable[] =
2284 0x0BE6, /* No Tamil 0 */
2285 0x0F29, /* No Tibetan half zero (out of sequence) */
2286 0x2473, /* No Bracketed 0 */
2287 0x2487, /* No 0 Full stop */
2288 0x2775, /* No inverted circled 0 */
2289 0x277F, /* No patterned circled */
2290 0x2789, /* No inverted Patterned circled */
2291 0x3020, /* No Hangzhou 0 */
2292 '\0' /* Terminator */
2294 static const WCHAR foldczone_src[] =
2296 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2297 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2299 static const WCHAR foldczone_dst[] =
2301 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2303 static const WCHAR foldczone_todo_src[] =
2305 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2307 static const WCHAR foldczone_todo_dst[] =
2309 0x3cb,0x1f0,' ','a',0
2311 static const WCHAR foldczone_todo_broken_dst[] =
2313 0x3cb,0x1f0,0xa0,0xaa,0
2315 static const WCHAR ligatures_src[] =
2317 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2318 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2319 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2320 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2321 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2322 0xfb04, 0xfb05, 0xfb06, '\0'
2324 static const WCHAR ligatures_dst[] =
2326 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2327 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2328 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2329 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2330 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2331 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2334 if (!pFoldStringW)
2336 win_skip("FoldStringW is not available\n");
2337 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2340 /* Invalid flag combinations */
2341 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2343 src[0] = dst[0] = '\0';
2344 SetLastError(0);
2345 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2346 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2348 win_skip("FoldStringW is not implemented\n");
2349 return;
2351 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2352 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2355 /* src & dst cannot be the same */
2356 SetLastError(0);
2357 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2358 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2359 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2361 /* src can't be NULL */
2362 SetLastError(0);
2363 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2364 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2365 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2367 /* srclen can't be 0 */
2368 SetLastError(0);
2369 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2370 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2371 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2373 /* dstlen can't be < 0 */
2374 SetLastError(0);
2375 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2376 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2377 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2379 /* Ret includes terminating NUL which is appended if srclen = -1 */
2380 SetLastError(0);
2381 src[0] = 'A';
2382 src[1] = '\0';
2383 dst[0] = '\0';
2384 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2385 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2386 ok(dst[0] == 'A' && dst[1] == '\0',
2387 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2388 'A', '\0', ret, dst[0], dst[1], GetLastError());
2390 /* If size is given, result is not NUL terminated */
2391 SetLastError(0);
2392 src[0] = 'A';
2393 src[1] = 'A';
2394 dst[0] = 'X';
2395 dst[1] = 'X';
2396 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2397 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2398 ok(dst[0] == 'A' && dst[1] == 'X',
2399 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2400 'A','X', ret, dst[0], dst[1], GetLastError());
2402 /* MAP_FOLDDIGITS */
2403 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2405 /* Check everything before this range */
2406 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2408 SetLastError(0);
2409 src[0] = ch;
2410 src[1] = dst[0] = '\0';
2411 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2412 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2414 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2415 /* Wine (correctly) maps all Unicode 4.0+ digits */
2416 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2417 (ch >= 0x1369 && ch <= 0x1371),
2418 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2421 if (digitRanges[j] == 0xffff)
2422 break; /* Finished the whole code point space */
2424 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2426 WCHAR c;
2428 /* Map out of sequence characters */
2429 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2430 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2431 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2432 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2433 else c = ch;
2434 SetLastError(0);
2435 src[0] = c;
2436 src[1] = dst[0] = '\0';
2437 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2438 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2440 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2441 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2442 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2443 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2444 strchrW(noDigitAvailable, c),
2445 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2446 ch, '0' + digitRanges[j] - ch, dst[0]);
2448 prev_ch = ch;
2451 /* MAP_FOLDCZONE */
2452 SetLastError(0);
2453 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2454 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2455 "Got %d, error %d\n", ret, GetLastError());
2456 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2457 "MAP_FOLDCZONE: Expanded incorrectly\n");
2459 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2460 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2461 "Got %d, error %d\n", ret, GetLastError());
2462 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2463 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2464 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2466 /* MAP_EXPAND_LIGATURES */
2467 SetLastError(0);
2468 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2469 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2470 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2471 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2472 "Got %d, error %d\n", ret, GetLastError());
2473 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2474 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2477 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2482 #define LCID_OK(l) \
2483 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2484 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2485 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2486 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2487 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2489 static void test_ConvertDefaultLocale(void)
2491 LCID lcid;
2493 /* Doesn't change lcid, even if non default sublang/sort used */
2494 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2495 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2496 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2497 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2499 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2500 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2501 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2502 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2503 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2505 /* Invariant language is not treated specially */
2506 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2508 /* User/system default languages alone are not mapped */
2509 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2510 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2512 /* Default lcids */
2513 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2514 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2515 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2518 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2519 DWORD dwFlags, LONG_PTR lParam)
2521 trace("%08x, %s, %s, %08x, %08lx\n",
2522 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2524 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2525 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2527 /* If lParam is one, we are calling with flags defaulted from 0 */
2528 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2529 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2531 return TRUE;
2534 static void test_EnumSystemLanguageGroupsA(void)
2536 BOOL ret;
2538 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2540 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2541 return;
2544 /* No enumeration proc */
2545 SetLastError(0);
2546 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2547 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2549 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2550 return;
2552 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2553 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2555 /* Invalid flags */
2556 SetLastError(0);
2557 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2558 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2560 /* No flags - defaults to LGRPID_INSTALLED */
2561 SetLastError(0xdeadbeef);
2562 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2563 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2565 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2566 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2569 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2571 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2572 return TRUE;
2575 static void test_EnumSystemLocalesEx(void)
2577 BOOL ret;
2579 if (!pEnumSystemLocalesEx)
2581 win_skip( "EnumSystemLocalesEx not available\n" );
2582 return;
2584 SetLastError( 0xdeadbeef );
2585 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2586 ok( !ret, "should have failed\n" );
2587 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2588 SetLastError( 0xdeadbeef );
2589 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2590 ok( ret, "failed err %u\n", GetLastError() );
2593 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2594 LONG_PTR lParam)
2596 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2598 /* invalid locale enumerated on some platforms */
2599 if (lcid == 0)
2600 return TRUE;
2602 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2603 "Enumerated grp %d not valid\n", lgrpid);
2604 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2605 "Enumerated grp locale %d not valid\n", lcid);
2606 return TRUE;
2609 static void test_EnumLanguageGroupLocalesA(void)
2611 BOOL ret;
2613 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2615 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2616 return;
2619 /* No enumeration proc */
2620 SetLastError(0);
2621 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2622 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2624 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2625 return;
2627 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2628 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2630 /* lgrpid too small */
2631 SetLastError(0);
2632 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2633 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2634 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2636 /* lgrpid too big */
2637 SetLastError(0);
2638 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2639 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2640 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2642 /* dwFlags is reserved */
2643 SetLastError(0);
2644 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2645 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2646 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2648 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2651 static void test_SetLocaleInfoA(void)
2653 BOOL bRet;
2654 LCID lcid = GetUserDefaultLCID();
2656 /* Null data */
2657 SetLastError(0);
2658 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2659 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2660 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2662 /* IDATE */
2663 SetLastError(0);
2664 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2665 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2666 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2668 /* ILDATE */
2669 SetLastError(0);
2670 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2671 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2672 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2675 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2677 trace("%s %08lx\n", value, lParam);
2678 return(TRUE);
2681 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2683 ok(!enumCount, "callback called again unexpected\n");
2684 enumCount++;
2685 return(FALSE);
2688 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2690 ok(0,"callback called unexpected\n");
2691 return(FALSE);
2694 static void test_EnumUILanguageA(void)
2696 BOOL ret;
2697 if (!pEnumUILanguagesA) {
2698 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2699 return;
2702 SetLastError(ERROR_SUCCESS);
2703 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2704 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2706 win_skip("EnumUILanguagesA is not implemented\n");
2707 return;
2709 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2711 enumCount = 0;
2712 SetLastError(ERROR_SUCCESS);
2713 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2716 SetLastError(ERROR_SUCCESS);
2717 ret = pEnumUILanguagesA(NULL, 0, 0);
2718 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2719 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2720 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2722 SetLastError(ERROR_SUCCESS);
2723 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2724 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2725 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2727 SetLastError(ERROR_SUCCESS);
2728 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2729 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2730 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2731 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2734 static char date_fmt_buf[1024];
2736 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2738 lstrcatA(date_fmt_buf, fmt);
2739 lstrcatA(date_fmt_buf, "\n");
2740 return TRUE;
2743 static void test_EnumDateFormatsA(void)
2745 char *p, buf[256];
2746 BOOL ret;
2747 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2749 trace("EnumDateFormatsA 0\n");
2750 date_fmt_buf[0] = 0;
2751 SetLastError(0xdeadbeef);
2752 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2753 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2755 win_skip("0 for dwFlags is not supported\n");
2757 else
2759 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2760 trace("%s\n", date_fmt_buf);
2761 /* test the 1st enumerated format */
2762 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2763 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2764 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2765 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2768 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2769 date_fmt_buf[0] = 0;
2770 SetLastError(0xdeadbeef);
2771 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2772 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2774 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2776 else
2778 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2779 trace("%s\n", date_fmt_buf);
2780 /* test the 1st enumerated format */
2781 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2782 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2783 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2784 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2787 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2788 date_fmt_buf[0] = 0;
2789 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2790 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2791 trace("%s\n", date_fmt_buf);
2792 /* test the 1st enumerated format */
2793 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2794 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2795 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2796 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2798 trace("EnumDateFormatsA DATE_LONGDATE\n");
2799 date_fmt_buf[0] = 0;
2800 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2801 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2802 trace("%s\n", date_fmt_buf);
2803 /* test the 1st enumerated format */
2804 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2805 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2806 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2807 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2809 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2810 date_fmt_buf[0] = 0;
2811 SetLastError(0xdeadbeef);
2812 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2813 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2815 skip("DATE_YEARMONTH is only present on W2K and later\n");
2816 return;
2818 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2819 trace("%s\n", date_fmt_buf);
2820 /* test the 1st enumerated format */
2821 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2822 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2823 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2824 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2825 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2828 static void test_EnumTimeFormatsA(void)
2830 char *p, buf[256];
2831 BOOL ret;
2832 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2834 trace("EnumTimeFormatsA 0\n");
2835 date_fmt_buf[0] = 0;
2836 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2837 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2838 trace("%s\n", date_fmt_buf);
2839 /* test the 1st enumerated format */
2840 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2841 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2842 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2843 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2845 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2846 date_fmt_buf[0] = 0;
2847 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2848 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2849 trace("%s\n", date_fmt_buf);
2850 /* test the 1st enumerated format */
2851 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2852 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2853 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2854 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2857 static void test_GetCPInfo(void)
2859 BOOL ret;
2860 CPINFO cpinfo;
2862 SetLastError(0xdeadbeef);
2863 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2864 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2865 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2866 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2868 SetLastError(0xdeadbeef);
2869 ret = GetCPInfo(CP_UTF7, &cpinfo);
2870 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2872 skip("Codepage CP_UTF7 is not installed/available\n");
2874 else
2876 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2877 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2878 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2879 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2880 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2881 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2884 SetLastError(0xdeadbeef);
2885 ret = GetCPInfo(CP_UTF8, &cpinfo);
2886 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2888 skip("Codepage CP_UTF8 is not installed/available\n");
2890 else
2892 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2893 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2894 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2895 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2896 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2897 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2898 "expected 4, got %u\n", cpinfo.MaxCharSize);
2903 * The CT_TYPE1 has varied over windows version.
2904 * The current target for correct behavior is windows 7.
2905 * There was a big shift between windows 2000 (first introduced) and windows Xp
2906 * Most of the old values below are from windows 2000.
2907 * A smaller subset of changes happened between windows Xp and Window vista/7
2909 static void test_GetStringTypeW(void)
2911 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2912 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2913 C1_SPACE | C1_BLANK | C1_DEFINED,
2914 C1_SPACE | C1_BLANK | C1_DEFINED,
2915 C1_SPACE | C1_BLANK | C1_DEFINED,
2916 C1_CNTRL | C1_BLANK | C1_DEFINED};
2917 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2918 C1_SPACE | C1_BLANK,
2919 C1_SPACE | C1_BLANK,
2920 C1_SPACE | C1_BLANK,
2921 C1_SPACE | C1_BLANK};
2923 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2925 /* Lu, Ll, Lt */
2926 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2927 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2928 C1_LOWER | C1_ALPHA,
2929 C1_UPPER | C1_LOWER | C1_ALPHA,
2930 C1_ALPHA};
2932 /* Sk, Sk, Mn, So, Me */
2933 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2934 /* Sc, Sm, No,*/
2935 0xffe0, 0xffe9, 0x2153};
2937 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2938 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2939 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2940 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2941 C1_ALPHA | C1_DEFINED,
2942 C1_CNTRL | C1_DEFINED,
2943 C1_PUNCT | C1_DEFINED,
2944 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2945 C1_ALPHA | C1_LOWER | C1_DEFINED,
2946 C1_ALPHA | C1_DEFINED };
2947 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2948 C1_ALPHA | C1_DEFINED,
2949 C1_CNTRL | C1_DEFINED,
2950 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2951 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2952 C1_ALPHA | C1_DEFINED,
2953 C1_DEFINED
2955 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2956 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2958 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2959 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2960 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2961 static const WCHAR lower_special[] = {0x2071, 0x207f};
2962 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2963 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2964 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2965 0xfff9, 0xfffa, 0xfffb};
2966 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2968 WORD types[20];
2969 int i;
2971 memset(types,0,sizeof(types));
2972 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2973 for (i = 0; i < 5; i++)
2974 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]);
2976 memset(types,0,sizeof(types));
2977 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2978 for (i = 0; i < 3; i++)
2979 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]));
2980 memset(types,0,sizeof(types));
2981 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2982 for (i = 0; i < 5; i++)
2983 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2985 memset(types,0,sizeof(types));
2986 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2987 for (i = 0; i < 8; i++)
2988 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);
2990 memset(types,0,sizeof(types));
2991 GetStringTypeW(CT_CTYPE1, changed, 7, types);
2992 for (i = 0; i < 7; i++)
2993 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]);
2995 memset(types,0,sizeof(types));
2996 GetStringTypeW(CT_CTYPE1, punct, 7, types);
2997 for (i = 0; i < 7; i++)
2998 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));
3001 memset(types,0,sizeof(types));
3002 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3003 for (i = 0; i < 12; i++)
3004 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);
3006 memset(types,0,sizeof(types));
3007 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3008 for (i = 0; i < 3; i++)
3009 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);
3011 memset(types,0,sizeof(types));
3012 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3013 for (i = 0; i < 2; i++)
3014 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);
3016 memset(types,0,sizeof(types));
3017 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
3018 for (i = 0; i < 20; i++)
3019 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);
3021 memset(types,0,sizeof(types));
3022 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
3023 for (i = 0; i < 3; i++)
3024 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 );
3027 static void test_IdnToNameprepUnicode(void)
3029 struct {
3030 DWORD in_len;
3031 const WCHAR in[64];
3032 DWORD ret;
3033 const WCHAR out[64];
3034 DWORD flags;
3035 DWORD err;
3036 DWORD todo;
3037 } test_data[] = {
3039 5, {'t','e','s','t',0},
3040 5, {'t','e','s','t',0},
3041 0, 0xdeadbeef
3044 3, {'a',0xe111,'b'},
3045 0, {0},
3046 0, ERROR_INVALID_NAME
3049 4, {'t',0,'e',0},
3050 0, {0},
3051 0, ERROR_INVALID_NAME
3054 1, {'T',0},
3055 1, {'T',0},
3056 0, 0xdeadbeef
3059 1, {0},
3060 0, {0},
3061 0, ERROR_INVALID_NAME
3064 6, {' ','-','/','[',']',0},
3065 6, {' ','-','/','[',']',0},
3066 0, 0xdeadbeef
3069 3, {'a','-','a'},
3070 3, {'a','-','a'},
3071 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
3074 3, {'a','a','-'},
3075 0, {0},
3076 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
3078 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
3079 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
3080 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
3081 0, 0xdeadbeef, TRUE
3084 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
3085 2, {'t',0},
3086 0, 0xdeadbeef
3088 { /* Another example of incorrectly working FoldString (composition) */
3089 2, {0x3b0, 0},
3090 2, {0x3b0, 0},
3091 0, 0xdeadbeef, TRUE
3094 2, {0x221, 0},
3095 0, {0},
3096 0, ERROR_NO_UNICODE_TRANSLATION
3099 2, {0x221, 0},
3100 2, {0x221, 0},
3101 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3104 5, {'a','.','.','a',0},
3105 0, {0},
3106 0, ERROR_INVALID_NAME
3109 3, {'a','.',0},
3110 3, {'a','.',0},
3111 0, 0xdeadbeef
3115 WCHAR buf[1024];
3116 DWORD i, ret, err;
3118 if (!pIdnToNameprepUnicode)
3120 win_skip("IdnToNameprepUnicode is not available\n");
3121 return;
3124 ret = pIdnToNameprepUnicode(0, test_data[0].in,
3125 test_data[0].in_len, NULL, 0);
3126 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3128 SetLastError(0xdeadbeef);
3129 ret = pIdnToNameprepUnicode(0, test_data[1].in,
3130 test_data[1].in_len, NULL, 0);
3131 err = GetLastError();
3132 ok(ret == test_data[1].ret, "ret = %d\n", ret);
3133 ok(err == test_data[1].err, "err = %d\n", err);
3135 SetLastError(0xdeadbeef);
3136 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
3137 buf, sizeof(buf)/sizeof(WCHAR));
3138 err = GetLastError();
3139 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3140 ok(err == 0xdeadbeef, "err = %d\n", err);
3142 SetLastError(0xdeadbeef);
3143 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3144 buf, sizeof(buf)/sizeof(WCHAR));
3145 err = GetLastError();
3146 ok(ret == 0, "ret = %d\n", ret);
3147 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3149 SetLastError(0xdeadbeef);
3150 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3151 buf, sizeof(buf)/sizeof(WCHAR));
3152 err = GetLastError();
3153 ok(ret == 0, "ret = %d\n", ret);
3154 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3156 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3157 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3158 ok(ret == test_data[0].ret, "ret = %d\n", ret);
3160 SetLastError(0xdeadbeef);
3161 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3162 err = GetLastError();
3163 ok(ret == 0, "ret = %d\n", ret);
3164 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3166 SetLastError(0xdeadbeef);
3167 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3168 err = GetLastError();
3169 ok(ret == 0, "ret = %d\n", ret);
3170 ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3172 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3174 SetLastError(0xdeadbeef);
3175 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3176 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3177 err = GetLastError();
3178 if(!test_data[i].todo) {
3179 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3180 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3181 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3182 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3183 }else {
3184 todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3185 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3190 static void test_IdnToAscii(void)
3192 struct {
3193 DWORD in_len;
3194 const WCHAR in[64];
3195 DWORD ret;
3196 const WCHAR out[64];
3197 DWORD flags;
3198 DWORD err;
3199 } test_data[] = {
3201 5, {'T','e','s','t',0},
3202 5, {'T','e','s','t',0},
3203 0, 0xdeadbeef
3206 5, {'T','e',0x017c,'s','t',0},
3207 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3208 0, 0xdeadbeef
3211 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3212 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3213 0, 0xdeadbeef
3216 3, {0x0105,'.',0},
3217 9, {'x','n','-','-','2','d','a','.',0},
3218 0, 0xdeadbeef
3221 10, {'h','t','t','p',':','/','/','t',0x0106,0},
3222 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3223 0, 0xdeadbeef
3226 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3227 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3228 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3229 0, 0xdeadbeef
3232 2, {0x221,0},
3233 8, {'x','n','-','-','6','l','a',0},
3234 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3238 WCHAR buf[1024];
3239 DWORD i, ret, err;
3241 if (!pIdnToAscii)
3243 win_skip("IdnToAscii is not available\n");
3244 return;
3247 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3249 SetLastError(0xdeadbeef);
3250 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3251 test_data[i].in_len, buf, sizeof(buf));
3252 err = GetLastError();
3253 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3254 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3255 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3256 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3260 static void test_IdnToUnicode(void)
3262 struct {
3263 DWORD in_len;
3264 const WCHAR in[64];
3265 DWORD ret;
3266 const WCHAR out[64];
3267 DWORD flags;
3268 DWORD err;
3269 } test_data[] = {
3271 5, {'T','e','s','.',0},
3272 5, {'T','e','s','.',0},
3273 0, 0xdeadbeef
3276 2, {0x105,0},
3277 0, {0},
3278 0, ERROR_INVALID_NAME
3281 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3282 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3283 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3284 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3285 0x05d1,0x05e8,0x05d9,0x05ea,0},
3286 0, 0xdeadbeef
3289 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3290 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3291 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3292 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3293 0, 0xdeadbeef
3296 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3297 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3298 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3299 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3300 0, {0},
3301 0, ERROR_INVALID_NAME
3304 8, {'x','n','-','-','6','l','a',0},
3305 2, {0x221,0},
3306 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3310 WCHAR buf[1024];
3311 DWORD i, ret, err;
3313 if (!pIdnToUnicode)
3315 win_skip("IdnToUnicode is not available\n");
3316 return;
3319 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3321 SetLastError(0xdeadbeef);
3322 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3323 test_data[i].in_len, buf, sizeof(buf));
3324 err = GetLastError();
3325 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3326 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3327 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3328 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3332 static void test_GetLocaleInfoEx(void)
3334 static const WCHAR enW[] = {'e','n',0};
3335 WCHAR bufferW[80];
3336 INT ret;
3338 if (!pGetLocaleInfoEx)
3340 win_skip("GetLocaleInfoEx not supported\n");
3341 return;
3344 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3345 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
3346 if (ret)
3348 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
3349 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
3350 static const WCHAR enusW[] = {'e','n','-','U','S',0};
3351 static const WCHAR usaW[] = {'U','S','A',0};
3352 static const WCHAR enuW[] = {'E','N','U',0};
3353 const struct neutralsublang_name_t *ptr = neutralsublang_names;
3354 DWORD val;
3356 todo_wine
3357 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
3359 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3360 ok(ret, "got %d\n", ret);
3361 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
3363 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3364 ok(ret, "got %d\n", ret);
3365 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
3367 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3368 ok(ret, "got %d\n", ret);
3369 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
3371 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3372 ok(ret, "got %d\n", ret);
3373 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
3375 bufferW[0] = 0;
3376 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
3377 todo_wine
3378 ok(!ret, "got %d\n", ret);
3380 while (*ptr->name)
3382 val = 0;
3383 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
3384 todo_wine
3385 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
3386 ptr++;
3391 START_TEST(locale)
3393 InitFunctionPointers();
3396 test_EnumTimeFormatsA();
3397 test_EnumDateFormatsA();
3398 test_GetLocaleInfoA();
3399 test_GetLocaleInfoW();
3400 test_GetLocaleInfoEx();
3401 test_GetTimeFormatA();
3402 test_GetDateFormatA();
3403 test_GetDateFormatW();
3404 test_GetCurrencyFormatA(); /* Also tests the W version */
3405 test_GetNumberFormatA(); /* Also tests the W version */
3406 test_CompareStringA();
3407 test_LCMapStringA();
3408 test_LCMapStringW();
3409 test_LCMapStringEx();
3410 test_LocaleNameToLCID();
3411 test_FoldStringA();
3412 test_FoldStringW();
3413 test_ConvertDefaultLocale();
3414 test_EnumSystemLanguageGroupsA();
3415 test_EnumSystemLocalesEx();
3416 test_EnumLanguageGroupLocalesA();
3417 test_SetLocaleInfoA();
3418 test_EnumUILanguageA();
3419 test_GetCPInfo();
3420 test_GetStringTypeW();
3421 test_IdnToNameprepUnicode();
3422 test_IdnToAscii();
3423 test_IdnToUnicode();
3424 /* this requires collation table patch to make it MS compatible */
3425 if (0) test_sorting();