push ac8730bd9057ca84ecf262ddc5d43fb7b5849da7
[wine/hacks.git] / dlls / kernel32 / tests / locale.c
blob0077db2af716934b127360e314992fef181fc3fd
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>
32 #include "wine/test.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winnls.h"
38 static inline unsigned int strlenW( const WCHAR *str )
40 const WCHAR *s = str;
41 while (*s) s++;
42 return s - str;
45 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
47 if (n <= 0) return 0;
48 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
49 return *str1 - *str2;
52 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
54 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
55 return NULL;
58 static inline int isdigitW( WCHAR wc )
60 WORD type;
61 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
62 return type & C1_DIGIT;
65 /* Some functions are only in later versions of kernel32.dll */
66 static HMODULE hKernel32;
67 static WORD enumCount;
69 typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
70 DWORD, LONG_PTR);
71 static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
72 typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
73 LGRPID, DWORD, LONG_PTR);
74 static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
75 typedef BOOL (WINAPI *EnumUILanguagesAFn)(UILANGUAGE_ENUMPROC,
76 DWORD, LONG_PTR);
77 static EnumUILanguagesAFn pEnumUILanguagesA;
79 typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
80 static FoldStringAFn pFoldStringA;
81 typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
82 static FoldStringWFn pFoldStringW;
84 typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
85 static IsValidLanguageGroupFn pIsValidLanguageGroup;
87 static void InitFunctionPointers(void)
89 hKernel32 = GetModuleHandleA("kernel32");
90 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
91 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
92 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
93 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
94 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
95 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
98 #define eq(received, expected, label, type) \
99 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
100 (label), (received), (expected))
102 #define BUFFER_SIZE 128
103 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
105 #define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (int)(len), ret)
106 #define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
107 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError())
108 #define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
109 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError())
110 #define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
111 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError())
112 #define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
113 GetLastError() == ERROR_INVALID_PARAMETER, \
114 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError())
115 #define EXPECT_LASTERROR_0 ok(GetLastError() == 0, \
116 "Expected GetLastError() == 0, got %d\n", GetLastError())
117 #define EXPECT_VALID ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError())
119 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
120 #define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
121 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
122 "Expected '%s', got '%s'\n", Expected, buffer)
124 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
125 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
126 SetLastError(0); buffer[0] = '\0'
127 #define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
128 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
129 #define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n")
130 #define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n")
132 #define NUO LOCALE_NOUSEROVERRIDE
134 static void test_GetLocaleInfoA(void)
136 int ret;
137 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
138 char buffer[BUFFER_SIZE];
140 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
142 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
143 * partially fill the buffer even if it is too short. See bug 637.
145 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
146 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
147 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
149 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
150 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
151 EXPECT_BUFFER; EXPECT_LEN(0);
152 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
154 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
155 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
156 EXPECT_VALID; EXPECT_LEN(7);
157 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
160 static void test_GetTimeFormatA(void)
162 int ret;
163 SYSTEMTIME curtime;
164 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
165 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
167 memset(&curtime, 2, sizeof(SYSTEMTIME));
168 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
169 SetLastError(0xdeadbeef);
170 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
171 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
173 curtime.wHour = 8;
174 curtime.wMinute = 56;
175 curtime.wSecond = 13;
176 curtime.wMilliseconds = 22;
177 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
178 SetLastError(0xdeadbeef);
179 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
180 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
182 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
183 SetLastError(0xdeadbeef);
184 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
185 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
187 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
188 SetLastError(0xdeadbeef);
189 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
190 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
192 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
193 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
194 EXPECT_VALID; EXPECT_LENA;
196 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
197 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
198 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
200 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
201 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
202 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
204 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
205 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
206 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
208 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
209 strcpy(Expected, "8:56 AM");
210 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
211 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
213 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
214 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
215 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
217 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
218 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
219 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
221 STRINGSA("t/tt", "A/AM"); /* AM time marker */
222 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
223 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
225 curtime.wHour = 13;
226 STRINGSA("t/tt", "P/PM"); /* PM time marker */
227 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
228 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
230 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
231 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
232 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
234 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
235 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
236 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
238 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
239 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
240 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
242 curtime.wHour = 14; /* change this to 14 or 2pm */
243 curtime.wMinute = 5;
244 curtime.wSecond = 3;
245 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 */
246 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
247 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
249 curtime.wHour = 0;
250 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
251 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
252 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
254 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
255 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
256 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
258 /* try to convert formatting strings with more than two letters
259 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
260 * NOTE: We expect any letter for which there is an upper case value
261 * we should see a replacement. For letters that DO NOT have
262 * upper case values we should see NO REPLACEMENT.
264 curtime.wHour = 8;
265 curtime.wMinute = 56;
266 curtime.wSecond = 13;
267 curtime.wMilliseconds = 22;
268 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
269 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
270 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
271 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
273 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
274 strcpy(buffer, "text");
275 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
276 EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
278 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
279 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
280 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
281 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
283 STRINGSA("'''", "'"); /* invalid quoted string */
284 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
285 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
287 /* test that msdn suggested single quotation usage works as expected */
288 STRINGSA("''''", "'"); /* single quote mark */
289 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
290 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
292 STRINGSA("''HHHHHH", "08"); /* Normal use */
293 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
294 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
296 /* and test for normal use of the single quotation mark */
297 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
298 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
299 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
301 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
302 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
303 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
305 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
306 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
307 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
309 curtime.wHour = 25;
310 STRINGSA("'123'tt", ""); /* Invalid time */
311 SetLastError(0xdeadbeef);
312 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
313 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
315 curtime.wHour = 12;
316 curtime.wMonth = 60; /* Invalid */
317 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
318 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
319 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
322 static void test_GetDateFormatA(void)
324 int ret;
325 SYSTEMTIME curtime;
326 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
327 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
329 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
330 STRINGSA("ddd',' MMM dd yy","");
331 SetLastError(0xdeadbeef);
332 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
333 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
335 curtime.wYear = 2002;
336 curtime.wMonth = 5;
337 curtime.wDay = 4;
338 curtime.wDayOfWeek = 3;
339 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
340 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
341 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
343 /* Same as above but with LOCALE_NOUSEROVERRIDE */
344 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
345 SetLastError(0xdeadbeef);
346 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
347 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
349 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
350 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
351 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
353 curtime.wHour = 36; /* Invalid */
354 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
355 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
356 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
358 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
359 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
360 EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA;
362 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
363 SetLastError(0xdeadbeef);
364 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
365 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
367 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
368 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
369 EXPECT_VALID; EXPECT_LENA;
370 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
371 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
373 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
374 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
375 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
377 /* test for expected DATE_YEARMONTH behavior with null format */
378 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
379 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
380 SetLastError(0xdeadbeef);
381 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
382 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
384 /* Test that using invalid DATE_* flags results in the correct error */
385 /* and return values */
386 STRINGSA("m/d/y", ""); /* Invalid flags */
387 SetLastError(0xdeadbeef);
388 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
389 &curtime, input, buffer, COUNTOF(buffer));
390 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
393 static void test_GetDateFormatW(void)
395 int ret;
396 SYSTEMTIME curtime;
397 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
398 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
400 STRINGSW("",""); /* If flags is not zero then format must be NULL */
401 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
402 input, buffer, COUNTOF(buffer));
403 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
404 return;
405 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW;
407 STRINGSW("",""); /* NULL buffer, len > 0 */
408 SetLastError(0xdeadbeef);
409 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
410 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
412 STRINGSW("",""); /* NULL buffer, len == 0 */
413 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
414 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
416 curtime.wYear = 2002;
417 curtime.wMonth = 10;
418 curtime.wDay = 23;
419 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
420 curtime.wHour = 65432; /* Invalid */
421 curtime.wMinute = 34512; /* Invalid */
422 curtime.wSecond = 65535; /* Invalid */
423 curtime.wMilliseconds = 12345;
424 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
425 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
426 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
428 /* Limit tests */
430 curtime.wYear = 1601;
431 curtime.wMonth = 1;
432 curtime.wDay = 1;
433 curtime.wDayOfWeek = 0; /* Irrelevant */
434 curtime.wHour = 0;
435 curtime.wMinute = 0;
436 curtime.wSecond = 0;
437 curtime.wMilliseconds = 0;
438 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
439 SetLastError(0xdeadbeef);
440 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
441 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
443 curtime.wYear = 1600;
444 curtime.wMonth = 12;
445 curtime.wDay = 31;
446 curtime.wDayOfWeek = 0; /* Irrelevant */
447 curtime.wHour = 23;
448 curtime.wMinute = 59;
449 curtime.wSecond = 59;
450 curtime.wMilliseconds = 999;
451 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
452 SetLastError(0xdeadbeef);
453 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
454 EXPECT_INVALID;
458 #define CY_POS_LEFT 0
459 #define CY_POS_RIGHT 1
460 #define CY_POS_LEFT_SPACE 2
461 #define CY_POS_RIGHT_SPACE 3
463 static void test_GetCurrencyFormatA(void)
465 static char szDot[] = { '.', '\0' };
466 static char szComma[] = { ',', '\0' };
467 static char szDollar[] = { '$', '\0' };
468 int ret;
469 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
470 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
471 CURRENCYFMTA format;
473 memset(&format, 0, sizeof(format));
475 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
476 SetLastError(0xdeadbeef);
477 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
478 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
480 STRINGSA("23,53",""); /* Invalid character --> Error */
481 SetLastError(0xdeadbeef);
482 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
483 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
485 STRINGSA("--",""); /* Double '-' --> Error */
486 SetLastError(0xdeadbeef);
487 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
488 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
490 STRINGSA("0-",""); /* Trailing '-' --> Error */
491 SetLastError(0xdeadbeef);
492 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
493 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
495 STRINGSA("0..",""); /* Double '.' --> Error */
496 SetLastError(0xdeadbeef);
497 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
498 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
500 STRINGSA(" 0.1",""); /* Leading space --> Error */
501 SetLastError(0xdeadbeef);
502 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
503 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
505 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
506 SetLastError(0xdeadbeef);
507 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
508 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
510 STRINGSA("2353",""); /* Format and flags given --> Error */
511 SetLastError(0xdeadbeef);
512 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
513 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
515 STRINGSA("2353",""); /* Invalid format --> Error */
516 SetLastError(0xdeadbeef);
517 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
518 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
520 STRINGSA("2353","$2,353.00"); /* Valid number */
521 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
522 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
524 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
525 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
526 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
528 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
529 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
530 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
532 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
533 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
534 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
536 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
537 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
538 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
540 format.NumDigits = 0; /* No decimal separator */
541 format.LeadingZero = 0;
542 format.Grouping = 0; /* No grouping char */
543 format.NegativeOrder = 0;
544 format.PositiveOrder = CY_POS_LEFT;
545 format.lpDecimalSep = szDot;
546 format.lpThousandSep = szComma;
547 format.lpCurrencySymbol = szDollar;
549 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
550 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
551 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
553 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
554 STRINGSA("2353","$2353.0");
555 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
556 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
558 format.Grouping = 2; /* Group by 100's */
559 STRINGSA("2353","$23,53.0");
560 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
561 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
563 format.LeadingZero = 1; /* Always provide leading zero */
564 STRINGSA(".5","$0.5");
565 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
566 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
568 format.PositiveOrder = CY_POS_RIGHT;
569 STRINGSA("1","1.0$");
570 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
571 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
573 format.PositiveOrder = CY_POS_LEFT_SPACE;
574 STRINGSA("1","$ 1.0");
575 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
576 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
578 format.PositiveOrder = CY_POS_RIGHT_SPACE;
579 STRINGSA("1","1.0 $");
580 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
581 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
583 format.NegativeOrder = 0;
584 STRINGSA("-1","($1.0)");
585 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
586 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
588 format.NegativeOrder = 1;
589 STRINGSA("-1","-$1.0");
590 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
591 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
593 format.NegativeOrder = 2;
594 STRINGSA("-1","$-1.0");
595 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
596 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
598 format.NegativeOrder = 3;
599 STRINGSA("-1","$1.0-");
600 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
601 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
603 format.NegativeOrder = 4;
604 STRINGSA("-1","(1.0$)");
605 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
606 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
608 format.NegativeOrder = 5;
609 STRINGSA("-1","-1.0$");
610 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
611 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
613 format.NegativeOrder = 6;
614 STRINGSA("-1","1.0-$");
615 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
616 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
618 format.NegativeOrder = 7;
619 STRINGSA("-1","1.0$-");
620 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
621 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
623 format.NegativeOrder = 8;
624 STRINGSA("-1","-1.0 $");
625 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
626 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
628 format.NegativeOrder = 9;
629 STRINGSA("-1","-$ 1.0");
630 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
631 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
633 format.NegativeOrder = 10;
634 STRINGSA("-1","1.0 $-");
635 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
636 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
638 format.NegativeOrder = 11;
639 STRINGSA("-1","$ 1.0-");
640 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
641 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
643 format.NegativeOrder = 12;
644 STRINGSA("-1","$ -1.0");
645 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
646 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
648 format.NegativeOrder = 13;
649 STRINGSA("-1","1.0- $");
650 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
651 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
653 format.NegativeOrder = 14;
654 STRINGSA("-1","($ 1.0)");
655 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
656 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
658 format.NegativeOrder = 15;
659 STRINGSA("-1","(1.0 $)");
660 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
661 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
664 #define NEG_PARENS 0 /* "(1.1)" */
665 #define NEG_LEFT 1 /* "-1.1" */
666 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
667 #define NEG_RIGHT 3 /* "1.1-" */
668 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
670 static void test_GetNumberFormatA(void)
672 static char szDot[] = { '.', '\0' };
673 static char szComma[] = { ',', '\0' };
674 int ret;
675 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
676 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
677 NUMBERFMTA format;
679 memset(&format, 0, sizeof(format));
681 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
682 SetLastError(0xdeadbeef);
683 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
684 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
686 STRINGSA("23,53",""); /* Invalid character --> Error */
687 SetLastError(0xdeadbeef);
688 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
689 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
691 STRINGSA("--",""); /* Double '-' --> Error */
692 SetLastError(0xdeadbeef);
693 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
694 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
696 STRINGSA("0-",""); /* Trailing '-' --> Error */
697 SetLastError(0xdeadbeef);
698 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
699 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
701 STRINGSA("0..",""); /* Double '.' --> Error */
702 SetLastError(0xdeadbeef);
703 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
704 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
706 STRINGSA(" 0.1",""); /* Leading space --> Error */
707 SetLastError(0xdeadbeef);
708 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
709 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
711 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
712 SetLastError(0xdeadbeef);
713 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
714 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
716 STRINGSA("2353",""); /* Format and flags given --> Error */
717 SetLastError(0xdeadbeef);
718 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
719 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
721 STRINGSA("2353",""); /* Invalid format --> Error */
722 SetLastError(0xdeadbeef);
723 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
724 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
726 STRINGSA("2353","2,353.00"); /* Valid number */
727 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
728 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
730 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
731 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
732 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
734 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
735 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
736 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
738 STRINGSA("2353.1","2,353.10"); /* Valid real number */
739 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
740 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
742 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
743 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
744 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
746 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
747 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
748 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
750 format.NumDigits = 0; /* No decimal separator */
751 format.LeadingZero = 0;
752 format.Grouping = 0; /* No grouping char */
753 format.NegativeOrder = 0;
754 format.lpDecimalSep = szDot;
755 format.lpThousandSep = szComma;
757 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
758 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
759 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
761 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
762 STRINGSA("2353","2353.0");
763 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
764 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
766 format.Grouping = 2; /* Group by 100's */
767 STRINGSA("2353","23,53.0");
768 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
769 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
771 format.LeadingZero = 1; /* Always provide leading zero */
772 STRINGSA(".5","0.5");
773 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
774 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
776 format.NegativeOrder = NEG_PARENS;
777 STRINGSA("-1","(1.0)");
778 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
779 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
781 format.NegativeOrder = NEG_LEFT;
782 STRINGSA("-1","-1.0");
783 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
784 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
786 format.NegativeOrder = NEG_LEFT_SPACE;
787 STRINGSA("-1","- 1.0");
788 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
789 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
791 format.NegativeOrder = NEG_RIGHT;
792 STRINGSA("-1","1.0-");
793 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
794 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
796 format.NegativeOrder = NEG_RIGHT_SPACE;
797 STRINGSA("-1","1.0 -");
798 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
799 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
801 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
803 if (IsValidLocale(lcid, 0))
805 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
806 Expected[3] = 160; /* Non breaking space */
807 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
808 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
813 static void test_CompareStringA(void)
815 int ret;
816 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
818 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
819 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
821 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
822 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
824 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
825 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
827 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
828 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
830 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
832 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
833 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
835 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
836 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
838 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
839 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
841 /* test for CompareStringA flags */
842 SetLastError(0xdeadbeef);
843 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
844 ok(GetLastError() == ERROR_INVALID_FLAGS,
845 "unexpected error code %d\n", GetLastError());
846 ok(!ret, "CompareStringA must fail with invalid flag\n");
848 SetLastError(0xdeadbeef);
849 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
850 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
851 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
852 /* end of test for CompareStringA flags */
854 ret = lstrcmpA("", "");
855 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
857 ret = lstrcmpA(NULL, NULL);
858 ok (ret == 0, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
860 ret = lstrcmpA("", NULL);
861 ok (ret == 1, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
863 ret = lstrcmpA(NULL, "");
864 ok (ret == -1, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
866 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
867 ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
869 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
870 ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
872 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
873 ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
875 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
876 ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
878 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
879 ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
881 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
882 ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
884 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
885 ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
887 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
888 ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
890 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
891 ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
893 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
894 ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
896 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
897 ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
899 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
900 ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
902 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
903 ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
905 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
906 ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
908 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
909 ok( ret == 3, "a vs { expected 3, got %d\n", ret);
911 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
912 ok( ret == 3, "A vs { expected 3, got %d\n", ret);
914 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
915 ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
917 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
918 ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
920 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
921 ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
923 /* hyphen and apostrophe are treated differently depending on
924 * whether SORT_STRINGSORT specified or not
926 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
927 ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
929 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
930 ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
932 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
933 ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
935 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
936 ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
938 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
939 ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
941 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
942 ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
944 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
945 ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
947 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
948 ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
950 if (0) { /* this requires collation table patch to make it MS compatible */
951 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
952 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
954 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
955 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
957 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
958 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
960 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
961 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
963 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
964 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
966 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
967 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
969 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
970 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
972 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
973 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
975 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
976 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
978 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
979 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
981 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
982 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
984 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
985 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
988 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
989 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
991 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
992 ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
994 /* WinXP handles embedded NULLs differently than earlier versions */
995 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
996 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
998 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
999 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1001 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1002 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1004 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1005 ok(ret == CSTR_EQUAL || /* win2k */
1006 ret == CSTR_GREATER_THAN,
1007 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1009 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1010 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1013 static void test_LCMapStringA(void)
1015 int ret, ret2;
1016 char buf[256], buf2[256];
1017 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1018 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1019 static const char symbols_stripped[] = "justateststring1";
1021 SetLastError(0xdeadbeef);
1022 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1023 lower_case, -1, buf, sizeof(buf));
1024 ok(ret == lstrlenA(lower_case) + 1,
1025 "ret %d, error %d, expected value %d\n",
1026 ret, GetLastError(), lstrlenA(lower_case) + 1);
1027 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1029 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1030 upper_case, -1, buf, sizeof(buf));
1031 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1032 ok(GetLastError() == ERROR_INVALID_FLAGS,
1033 "unexpected error code %d\n", GetLastError());
1035 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1036 upper_case, -1, buf, sizeof(buf));
1037 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1038 ok(GetLastError() == ERROR_INVALID_FLAGS,
1039 "unexpected error code %d\n", GetLastError());
1041 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1042 upper_case, -1, buf, sizeof(buf));
1043 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1044 ok(GetLastError() == ERROR_INVALID_FLAGS,
1045 "unexpected error code %d\n", GetLastError());
1047 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1048 upper_case, -1, buf, sizeof(buf));
1049 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1050 ok(GetLastError() == ERROR_INVALID_FLAGS,
1051 "unexpected error code %d\n", GetLastError());
1053 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1054 SetLastError(0xdeadbeef);
1055 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1056 upper_case, -1, buf, sizeof(buf));
1057 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1058 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1060 /* test LCMAP_LOWERCASE */
1061 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1062 upper_case, -1, buf, sizeof(buf));
1063 ok(ret == lstrlenA(upper_case) + 1,
1064 "ret %d, error %d, expected value %d\n",
1065 ret, GetLastError(), lstrlenA(upper_case) + 1);
1066 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1068 /* test LCMAP_UPPERCASE */
1069 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1070 lower_case, -1, buf, sizeof(buf));
1071 ok(ret == lstrlenA(lower_case) + 1,
1072 "ret %d, error %d, expected value %d\n",
1073 ret, GetLastError(), lstrlenA(lower_case) + 1);
1074 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1076 /* test buffer overflow */
1077 SetLastError(0xdeadbeef);
1078 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1079 lower_case, -1, buf, 4);
1080 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1081 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1083 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1084 lstrcpyA(buf, lower_case);
1085 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1086 buf, -1, buf, sizeof(buf));
1087 if (!ret) /* Win9x */
1088 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1089 else
1091 ok(ret == lstrlenA(lower_case) + 1,
1092 "ret %d, error %d, expected value %d\n",
1093 ret, GetLastError(), lstrlenA(lower_case) + 1);
1094 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1096 lstrcpyA(buf, upper_case);
1097 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1098 buf, -1, buf, sizeof(buf));
1099 if (!ret) /* Win9x */
1100 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1101 else
1103 ok(ret == lstrlenA(upper_case) + 1,
1104 "ret %d, error %d, expected value %d\n",
1105 ret, GetLastError(), lstrlenA(lower_case) + 1);
1106 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1109 /* otherwise src == dst should fail */
1110 SetLastError(0xdeadbeef);
1111 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1112 buf, 10, buf, sizeof(buf));
1113 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1114 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1115 "unexpected error code %d\n", GetLastError());
1116 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1118 /* test whether '\0' is always appended */
1119 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1120 upper_case, -1, buf, sizeof(buf));
1121 ok(ret, "LCMapStringA must succeed\n");
1122 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1123 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1124 ok(ret, "LCMapStringA must succeed\n");
1125 ok(ret == ret2, "lengths of sort keys must be equal\n");
1126 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1128 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1129 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1130 upper_case, -1, buf, sizeof(buf));
1131 ok(ret, "LCMapStringA must succeed\n");
1132 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1133 lower_case, -1, buf2, sizeof(buf2));
1134 ok(ret2, "LCMapStringA must succeed\n");
1135 ok(ret == ret2, "lengths of sort keys must be equal\n");
1136 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1138 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1139 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1140 lower_case, -1, buf, sizeof(buf));
1141 ok(ret, "LCMapStringA must succeed\n");
1142 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1143 lower_case, -1, buf2, sizeof(buf2));
1144 ok(ret2, "LCMapStringA must succeed\n");
1145 ok(ret == ret2, "lengths of sort keys must be equal\n");
1146 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1148 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1149 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1150 lower_case, -1, buf, sizeof(buf));
1151 ok(ret, "LCMapStringA must succeed\n");
1152 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1153 symbols_stripped, -1, buf2, sizeof(buf2));
1154 ok(ret2, "LCMapStringA must succeed\n");
1155 ok(ret == ret2, "lengths of sort keys must be equal\n");
1156 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1158 /* test NORM_IGNORENONSPACE */
1159 lstrcpyA(buf, "foo");
1160 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1161 lower_case, -1, buf, sizeof(buf));
1162 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1163 lstrlenA(lower_case) + 1, ret);
1164 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1166 /* test NORM_IGNORESYMBOLS */
1167 lstrcpyA(buf, "foo");
1168 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1169 lower_case, -1, buf, sizeof(buf));
1170 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1171 lstrlenA(symbols_stripped) + 1, ret);
1172 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1174 /* test srclen = 0 */
1175 SetLastError(0xdeadbeef);
1176 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1177 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1178 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1179 "unexpected error code %d\n", GetLastError());
1182 static void test_LCMapStringW(void)
1184 int ret, ret2;
1185 WCHAR buf[256], buf2[256];
1186 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1187 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};
1188 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};
1189 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1190 static const WCHAR fooW[] = {'f','o','o',0};
1192 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1193 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1194 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1196 win_skip("LCMapStringW is not implemented\n");
1197 return;
1199 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1200 ok(GetLastError() == ERROR_INVALID_FLAGS,
1201 "unexpected error code %d\n", GetLastError());
1203 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1204 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1205 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1206 ok(GetLastError() == ERROR_INVALID_FLAGS,
1207 "unexpected error code %d\n", GetLastError());
1209 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1210 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1211 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1212 ok(GetLastError() == ERROR_INVALID_FLAGS,
1213 "unexpected error code %d\n", GetLastError());
1215 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1216 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1217 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1218 ok(GetLastError() == ERROR_INVALID_FLAGS,
1219 "unexpected error code %d\n", GetLastError());
1221 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1222 SetLastError(0xdeadbeef);
1223 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1224 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1225 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1226 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1228 /* test LCMAP_LOWERCASE */
1229 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1230 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1231 ok(ret == lstrlenW(upper_case) + 1,
1232 "ret %d, error %d, expected value %d\n",
1233 ret, GetLastError(), lstrlenW(upper_case) + 1);
1234 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1236 /* test LCMAP_UPPERCASE */
1237 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1238 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1239 ok(ret == lstrlenW(lower_case) + 1,
1240 "ret %d, error %d, expected value %d\n",
1241 ret, GetLastError(), lstrlenW(lower_case) + 1);
1242 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1244 /* test buffer overflow */
1245 SetLastError(0xdeadbeef);
1246 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1247 lower_case, -1, buf, 4);
1248 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1249 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1251 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1252 lstrcpyW(buf, lower_case);
1253 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1254 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1255 ok(ret == lstrlenW(lower_case) + 1,
1256 "ret %d, error %d, expected value %d\n",
1257 ret, GetLastError(), lstrlenW(lower_case) + 1);
1258 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1260 lstrcpyW(buf, upper_case);
1261 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1262 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1263 ok(ret == lstrlenW(upper_case) + 1,
1264 "ret %d, error %d, expected value %d\n",
1265 ret, GetLastError(), lstrlenW(lower_case) + 1);
1266 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1268 /* otherwise src == dst should fail */
1269 SetLastError(0xdeadbeef);
1270 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1271 buf, 10, buf, sizeof(buf));
1272 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1273 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1274 "unexpected error code %d\n", GetLastError());
1275 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1277 /* test whether '\0' is always appended */
1278 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1279 upper_case, -1, buf, sizeof(buf));
1280 ok(ret, "LCMapStringW must succeed\n");
1281 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1282 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1283 ok(ret, "LCMapStringW must succeed\n");
1284 ok(ret == ret2, "lengths of sort keys must be equal\n");
1285 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1287 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1288 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1289 upper_case, -1, buf, sizeof(buf));
1290 ok(ret, "LCMapStringW must succeed\n");
1291 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1292 lower_case, -1, buf2, sizeof(buf2));
1293 ok(ret2, "LCMapStringW must succeed\n");
1294 ok(ret == ret2, "lengths of sort keys must be equal\n");
1295 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1297 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1298 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1299 lower_case, -1, buf, sizeof(buf));
1300 ok(ret, "LCMapStringW must succeed\n");
1301 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1302 lower_case, -1, buf2, sizeof(buf2));
1303 ok(ret2, "LCMapStringW must succeed\n");
1304 ok(ret == ret2, "lengths of sort keys must be equal\n");
1305 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1307 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1308 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1309 lower_case, -1, buf, sizeof(buf));
1310 ok(ret, "LCMapStringW must succeed\n");
1311 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1312 symbols_stripped, -1, buf2, sizeof(buf2));
1313 ok(ret2, "LCMapStringW must succeed\n");
1314 ok(ret == ret2, "lengths of sort keys must be equal\n");
1315 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1317 /* test NORM_IGNORENONSPACE */
1318 lstrcpyW(buf, fooW);
1319 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1320 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1321 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1322 lstrlenW(lower_case) + 1, ret);
1323 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1325 /* test NORM_IGNORESYMBOLS */
1326 lstrcpyW(buf, fooW);
1327 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1328 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1329 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1330 lstrlenW(symbols_stripped) + 1, ret);
1331 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1333 /* test srclen = 0 */
1334 SetLastError(0xdeadbeef);
1335 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1336 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1337 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1338 "unexpected error code %d\n", GetLastError());
1341 /* this requires collation table patch to make it MS compatible */
1342 static const char * const strings_sorted[] =
1344 "'",
1345 "-",
1346 "!",
1347 "\"",
1348 ".",
1349 ":",
1350 "\\",
1351 "_",
1352 "`",
1353 "{",
1354 "}",
1355 "+",
1356 "0",
1357 "1",
1358 "2",
1359 "3",
1360 "4",
1361 "5",
1362 "6",
1363 "7",
1364 "8",
1365 "9",
1366 "a",
1367 "A",
1368 "b",
1369 "B",
1370 "c",
1374 static const char * const strings[] =
1376 "C",
1377 "\"",
1378 "9",
1379 "'",
1380 "}",
1381 "-",
1382 "7",
1383 "+",
1384 "`",
1385 "1",
1386 "a",
1387 "5",
1388 "\\",
1389 "8",
1390 "B",
1391 "3",
1392 "_",
1393 "6",
1394 "{",
1395 "2",
1396 "c",
1397 "4",
1398 "!",
1399 "0",
1400 "A",
1401 ":",
1402 "b",
1406 static int compare_string1(const void *e1, const void *e2)
1408 const char *s1 = *(const char *const *)e1;
1409 const char *s2 = *(const char *const *)e2;
1411 return lstrcmpA(s1, s2);
1414 static int compare_string2(const void *e1, const void *e2)
1416 const char *s1 = *(const char *const *)e1;
1417 const char *s2 = *(const char *const *)e2;
1419 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1422 static int compare_string3(const void *e1, const void *e2)
1424 const char *s1 = *(const char *const *)e1;
1425 const char *s2 = *(const char *const *)e2;
1426 char key1[256], key2[256];
1428 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1429 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1430 return strcmp(key1, key2);
1433 static void test_sorting(void)
1435 char buf[256];
1436 char **str_buf = (char **)buf;
1437 int i;
1439 assert(sizeof(buf) >= sizeof(strings));
1441 /* 1. sort using lstrcmpA */
1442 memcpy(buf, strings, sizeof(strings));
1443 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1444 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1446 ok(!strcmp(strings_sorted[i], str_buf[i]),
1447 "qsort using lstrcmpA failed for element %d\n", i);
1449 /* 2. sort using CompareStringA */
1450 memcpy(buf, strings, sizeof(strings));
1451 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1452 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1454 ok(!strcmp(strings_sorted[i], str_buf[i]),
1455 "qsort using CompareStringA failed for element %d\n", i);
1457 /* 3. sort using sort keys */
1458 memcpy(buf, strings, sizeof(strings));
1459 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1460 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1462 ok(!strcmp(strings_sorted[i], str_buf[i]),
1463 "qsort using sort keys failed for element %d\n", i);
1467 static void test_FoldStringA(void)
1469 int ret, i;
1470 char src[256], dst[256];
1471 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1472 static const char digits_dst[] = { '1','2','3','\0' };
1473 static const char composite_src[] =
1475 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1476 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1477 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1478 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1479 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1480 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1481 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1482 0xfb,0xfc,0xfd,0xff,'\0'
1484 static const char composite_dst[] =
1486 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1487 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1488 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1489 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1490 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1491 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1492 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1493 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1494 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1495 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1496 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1497 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1498 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1499 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1500 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1502 static const char ligatures_src[] =
1504 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1506 static const char ligatures_dst[] =
1508 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1511 if (!pFoldStringA)
1512 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1514 /* these tests are locale specific */
1515 if (GetACP() != 1252)
1517 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1518 return;
1521 /* MAP_FOLDDIGITS */
1522 SetLastError(0);
1523 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1524 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1525 return;
1526 EXPECT_LEN(4); EXPECT_VALID;
1527 ok(strcmp(dst, digits_dst) == 0,
1528 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1529 for (i = 1; i < 256; i++)
1531 if (!strchr(digits_src, i))
1533 src[0] = i;
1534 src[1] = '\0';
1535 SetLastError(0);
1536 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1537 EXPECT_LEN(2); EXPECT_VALID;
1538 ok(dst[0] == src[0],
1539 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1543 /* MAP_EXPAND_LIGATURES */
1544 SetLastError(0);
1545 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1546 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1547 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1548 EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
1549 ok(strcmp(dst, ligatures_dst) == 0,
1550 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1551 for (i = 1; i < 256; i++)
1553 if (!strchr(ligatures_src, i))
1555 src[0] = i;
1556 src[1] = '\0';
1557 SetLastError(0);
1558 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1559 EXPECT_LEN(2); EXPECT_VALID;
1560 ok(dst[0] == src[0],
1561 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1566 /* MAP_COMPOSITE */
1567 SetLastError(0);
1568 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1569 EXPECT_VALID;
1570 todo_wine
1572 /* Wine gets close, but doesn't produce quite the same result as native */
1573 EXPECT_LEN(121);
1574 ok(strcmp(dst, composite_dst) == 0,
1575 "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
1578 for (i = 1; i < 256; i++)
1580 if (!strchr(composite_src, i))
1582 src[0] = i;
1583 src[1] = '\0';
1584 SetLastError(0);
1585 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1586 EXPECT_LEN(2); EXPECT_VALID;
1587 ok(dst[0] == src[0],
1588 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1589 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1593 /* MAP_FOLDCZONE */
1594 for (i = 1; i < 256; i++)
1596 src[0] = i;
1597 src[1] = '\0';
1598 SetLastError(0);
1599 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1600 EXPECT_LEN(2); EXPECT_VALID;
1601 ok(src[0] == dst[0],
1602 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1603 (unsigned char)src[0], (unsigned char)dst[0]);
1606 /* MAP_PRECOMPOSED */
1607 for (i = 1; i < 256; i++)
1609 src[0] = i;
1610 src[1] = '\0';
1611 SetLastError(0);
1612 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1613 EXPECT_LEN(2); EXPECT_VALID;
1614 ok(src[0] == dst[0],
1615 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1616 (unsigned char)src[0], (unsigned char)dst[0]);
1620 static void test_FoldStringW(void)
1622 int ret;
1623 unsigned int i, j, failures;
1624 WCHAR src[256], dst[256], ch, prev_ch = 1;
1625 static const DWORD badFlags[] =
1628 MAP_PRECOMPOSED|MAP_COMPOSITE,
1629 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1630 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1632 /* Ranges of digits 0-9 : Must be sorted! */
1633 static const WCHAR digitRanges[] =
1635 0x0030, /* '0'-'9' */
1636 0x0660, /* Eastern Arabic */
1637 0x06F0, /* Arabic - Hindu */
1638 0x0966, /* Devengari */
1639 0x09E6, /* Bengalii */
1640 0x0A66, /* Gurmukhi */
1641 0x0AE6, /* Gujarati */
1642 0x0B66, /* Oriya */
1643 0x0BE6, /* Tamil - No 0 */
1644 0x0C66, /* Telugu */
1645 0x0CE6, /* Kannada */
1646 0x0D66, /* Maylayalam */
1647 0x0E50, /* Thai */
1648 0x0ED0, /* Laos */
1649 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1650 0x2080, /* Subscript */
1651 0x245F, /* Circled - 0 is out of sequence */
1652 0x2473, /* Bracketed */
1653 0x2487, /* Full stop */
1654 0x2775, /* Inverted circled - No 0 */
1655 0x277F, /* Patterned circled - No 0 */
1656 0x2789, /* Inverted Patterned circled - No 0 */
1657 0xff10, /* Pliene chasse (?) */
1658 0xffff /* Terminator */
1660 /* Digits which are represented, but out of sequence */
1661 static const WCHAR outOfSequenceDigits[] =
1663 0xB9, /* Superscript 1 */
1664 0xB2, /* Superscript 2 */
1665 0xB3, /* Superscript 3 */
1666 0x24EA, /* Circled 0 */
1667 '\0' /* Terminator */
1669 /* Digits in digitRanges for which no representation is available */
1670 static const WCHAR noDigitAvailable[] =
1672 0x0BE6, /* No Tamil 0 */
1673 0x2473, /* No Bracketed 0 */
1674 0x2487, /* No 0 Full stop */
1675 0x2775, /* No inverted circled 0 */
1676 0x277F, /* No patterned circled */
1677 0x2789, /* No inverted Patterned circled */
1678 '\0' /* Terminator */
1680 /* Compatibility conversion results */
1681 static const WCHAR compat_F900_FA2F[256+48] =
1683 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
1684 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
1685 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
1686 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
1687 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
1688 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
1689 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
1690 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
1691 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
1692 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
1693 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
1694 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
1695 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
1696 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
1697 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
1698 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
1699 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
1700 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
1701 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
1702 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
1703 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
1704 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
1705 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
1706 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
1707 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
1708 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
1709 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
1710 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
1711 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
1712 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
1713 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
1714 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
1715 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
1716 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
1717 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
1718 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
1719 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
1720 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
1722 static const WCHAR compat_FE30_FEF7[200] =
1724 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
1725 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
1726 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
1727 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
1728 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
1729 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
1730 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
1731 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
1732 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
1733 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
1734 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
1735 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
1736 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
1737 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
1738 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
1739 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
1740 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
1741 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
1742 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
1743 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
1744 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
1745 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
1746 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
1747 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
1748 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
1750 static const WCHAR compat_FF00_FFEF[240] =
1752 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1753 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1754 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1755 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
1756 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1757 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1758 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1759 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
1760 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1761 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1762 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1763 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1764 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
1765 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
1766 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
1767 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
1768 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
1769 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
1770 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
1771 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
1772 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
1773 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
1774 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
1775 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
1776 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
1777 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
1778 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
1779 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
1780 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
1781 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
1783 static const WCHAR ligatures_src[] =
1785 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1786 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1787 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1788 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
1789 0xfb04, 0xfb05, 0xfb06, '\0'
1791 static const WCHAR ligatures_dst[] =
1793 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
1794 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
1795 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
1796 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
1797 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
1800 if (!pFoldStringW)
1802 skip("FoldStringW is not available\n");
1803 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1806 /* Invalid flag combinations */
1807 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1809 src[0] = dst[0] = '\0';
1810 SetLastError(0);
1811 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1812 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1814 skip("FoldStringW is not implemented\n");
1815 return;
1817 EXPECT_LEN(0); EXPECT_FLAGS;
1820 /* src & dst cannot be the same */
1821 SetLastError(0);
1822 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
1823 EXPECT_LEN(0); EXPECT_INVALID;
1825 /* src can't be NULL */
1826 SetLastError(0);
1827 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1828 EXPECT_LEN(0); EXPECT_INVALID;
1830 /* srclen can't be 0 */
1831 SetLastError(0);
1832 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1833 EXPECT_LEN(0); EXPECT_INVALID;
1835 /* dstlen can't be < 0 */
1836 SetLastError(0);
1837 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1838 EXPECT_LEN(0); EXPECT_INVALID;
1840 /* Ret includes terminating NUL which is appended if srclen = -1 */
1841 SetLastError(0);
1842 src[0] = 'A';
1843 src[1] = '\0';
1844 dst[0] = '\0';
1845 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1846 EXPECT_LEN(2); EXPECT_VALID;
1847 ok(dst[0] == 'A' && dst[1] == '\0',
1848 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
1849 'A', '\0', ret, dst[0], dst[1], GetLastError());
1851 /* If size is given, result is not NUL terminated */
1852 SetLastError(0);
1853 src[0] = 'A';
1854 src[1] = 'A';
1855 dst[0] = 'X';
1856 dst[1] = 'X';
1857 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
1858 EXPECT_LEN(1); EXPECT_VALID;
1859 ok(dst[0] == 'A' && dst[1] == 'X',
1860 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
1861 'A','X', ret, dst[0], dst[1], GetLastError());
1863 /* MAP_FOLDDIGITS */
1864 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1866 /* Check everything before this range */
1867 for (ch = prev_ch; ch < digitRanges[j]; ch++)
1869 SetLastError(0);
1870 src[0] = ch;
1871 src[1] = dst[0] = '\0';
1872 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1873 EXPECT_LEN(2); EXPECT_VALID;
1875 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
1876 /* Wine (correctly) maps all Unicode 4.0+ digits */
1877 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
1878 (ch >= 0x1369 && ch <= 0x1371),
1879 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
1882 if (digitRanges[j] == 0xffff)
1883 break; /* Finished the whole code point space */
1885 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1887 WCHAR c;
1889 /* Map out of sequence characters */
1890 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
1891 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
1892 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
1893 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
1894 else c = ch;
1895 SetLastError(0);
1896 src[0] = c;
1897 src[1] = dst[0] = '\0';
1898 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1899 EXPECT_LEN(2); EXPECT_VALID;
1901 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
1902 strchrW(noDigitAvailable, c),
1903 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
1904 ch, '0' + digitRanges[j] - ch, dst[0]);
1906 prev_ch = ch;
1909 /* MAP_FOLDCZONE */
1910 for (ch = 1, failures = 0; ch <0xffff; ch++)
1912 WCHAR expected = 0;
1914 if (ch >= 0xF900 && ch <= 0xFA2F)
1915 expected = compat_F900_FA2F[ch - 0xF900];
1916 else if (ch >= 0xFE30 && ch <= 0xFEF7)
1917 expected = compat_FE30_FEF7[ch - 0xFE30];
1918 else if (ch >= 0xFF00 && ch <= 0xFFEF)
1919 expected = compat_FF00_FFEF[ch - 0xFF00];
1921 if (!expected)
1922 expected = ch;
1924 SetLastError(0);
1925 src[0] = ch;
1926 src[1] = dst[0] = '\0';
1927 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1928 EXPECT_LEN(2); EXPECT_VALID;
1929 ok(dst[0] == expected ||
1930 /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
1931 /* FIXME: But they should be re-checked */
1932 ch == 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 ||
1933 ch == 0xf9f1 ||
1934 (0xfa0c <= ch && ch <= 0xfa6a) ||
1935 (0xfa70 <= ch && ch <= 0xfad9) ||
1936 ch == 0xfe47 || ch == 0xfe48 || ch == 0xfe68 ||
1937 (0xfe70 <= ch && ch <= 0xfe7f) ||
1938 ch == 0xff3c || ch == 0xff5f || ch == 0xff60 ||
1939 ch == 0xff9e || ch == 0xff9f,
1940 "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
1941 ch, ch, expected, dst[0]);
1942 if (dst[0] != expected && ch < 0xf000 && ++failures > 50)
1944 trace( "MAP_FOLDCZONE: Too many failures, giving up\n" );
1945 break;
1949 /* MAP_EXPAND_LIGATURES */
1950 SetLastError(0);
1951 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1952 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1953 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1954 EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
1955 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
1956 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
1957 for (i = 1, failures = 0; i <= 0xffff; i++)
1959 if (!strchrW(ligatures_src, i))
1961 src[0] = i;
1962 src[1] = '\0';
1963 SetLastError(0);
1964 ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1965 EXPECT_LEN(2); EXPECT_VALID;
1966 if (ret == 3)
1967 ok(0, "MAP_EXPAND_LIGATURES: %04x : Expected %04x, got %04x %04x\n",
1968 i, src[0], dst[0], dst[1]);
1969 else
1970 ok(dst[0] == src[0],
1971 "MAP_EXPAND_LIGATURES: %04x : Expected %04x, got %04x\n",
1972 i, src[0], dst[0]);
1973 if (dst[0] != src[0] && ++failures > 50)
1975 trace( "MAP_EXPAND_LIGATURES: Too many failures, giving up\n" );
1976 break;
1982 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1987 #define LCID_OK(l) \
1988 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
1989 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
1990 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
1991 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
1992 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
1994 static void test_ConvertDefaultLocale(void)
1996 LCID lcid;
1998 /* Doesn't change lcid, even if non default sublang/sort used */
1999 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2000 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2001 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2002 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2004 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2005 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2006 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2007 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2008 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2009 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
2010 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
2012 /* Invariant language is not treated specially */
2013 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2014 LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
2015 MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
2017 /* User/system default languages alone are not mapped */
2018 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2019 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2021 /* Default lcids */
2022 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2023 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2024 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2027 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2028 DWORD dwFlags, LONG_PTR lParam)
2030 trace("%08x, %s, %s, %08x, %08lx\n",
2031 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2033 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2034 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2036 /* If lParam is one, we are calling with flags defaulted from 0 */
2037 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2038 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2040 return TRUE;
2043 static void test_EnumSystemLanguageGroupsA(void)
2045 BOOL ret;
2047 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2049 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2050 return;
2053 /* No enumeration proc */
2054 SetLastError(0);
2055 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2056 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2058 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2059 return;
2061 EXPECT_INVALID;
2063 /* Invalid flags */
2064 SetLastError(0);
2065 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2066 EXPECT_FLAGS;
2068 /* No flags - defaults to LGRPID_INSTALLED */
2069 SetLastError(0);
2070 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2071 EXPECT_LASTERROR_0;
2073 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2074 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2078 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2079 LONG_PTR lParam)
2081 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2083 /* invalid locale enumerated on some platforms */
2084 if (lcid == 0)
2085 return TRUE;
2087 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2088 "Enumerated grp %d not valid\n", lgrpid);
2089 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2090 "Enumerated grp locale %d not valid\n", lcid);
2091 return TRUE;
2094 static void test_EnumLanguageGroupLocalesA(void)
2096 BOOL ret;
2098 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2100 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2101 return;
2104 /* No enumeration proc */
2105 SetLastError(0);
2106 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2107 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2109 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2110 return;
2112 EXPECT_INVALID;
2114 /* lgrpid too small */
2115 SetLastError(0);
2116 pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2117 EXPECT_INVALID;
2119 /* lgrpid too big */
2120 SetLastError(0);
2121 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2122 EXPECT_INVALID;
2124 /* dwFlags is reserved */
2125 SetLastError(0);
2126 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2127 EXPECT_INVALID;
2129 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2132 static void test_SetLocaleInfoA(void)
2134 BOOL bRet;
2135 LCID lcid = GetUserDefaultLCID();
2137 /* Null data */
2138 SetLastError(0);
2139 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2140 EXPECT_INVALID;
2142 /* IDATE */
2143 SetLastError(0);
2144 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2145 EXPECT_FLAGS;
2147 /* ILDATE */
2148 SetLastError(0);
2149 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2150 EXPECT_FLAGS;
2153 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2155 trace("%s %08lx\n", value, lParam);
2156 return(TRUE);
2159 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2161 ok(!enumCount, "callback called again unexpected\n");
2162 enumCount++;
2163 return(FALSE);
2166 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2168 ok(0,"callback called unexpected\n");
2169 return(FALSE);
2172 static void test_EnumUILanguageA(void)
2174 BOOL ret;
2175 if (!pEnumUILanguagesA) {
2176 skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2177 return;
2180 SetLastError(ERROR_SUCCESS);
2181 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2182 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2184 win_skip("EnumUILanguagesA is not implemented\n");
2185 return;
2187 EXPECT_TRUE; EXPECT_VALID;
2189 enumCount = 0;
2190 SetLastError(ERROR_SUCCESS);
2191 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2192 EXPECT_TRUE; EXPECT_VALID;
2194 SetLastError(ERROR_SUCCESS);
2195 ret = pEnumUILanguagesA(NULL, 0, 0);
2196 EXPECT_FALSE; EXPECT_INVALID;
2198 SetLastError(ERROR_SUCCESS);
2199 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2200 EXPECT_FALSE; EXPECT_FLAGS;
2202 SetLastError(ERROR_SUCCESS);
2203 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2204 EXPECT_FALSE; EXPECT_INVALID;
2207 static char date_fmt_buf[1024];
2209 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2211 lstrcatA(date_fmt_buf, fmt);
2212 lstrcatA(date_fmt_buf, "\n");
2213 return TRUE;
2216 static void test_EnumDateFormatsA(void)
2218 char *p, buf[256];
2219 BOOL ret;
2220 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2222 trace("EnumDateFormatsA 0\n");
2223 date_fmt_buf[0] = 0;
2224 SetLastError(0xdeadbeef);
2225 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2226 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2228 win_skip("0 for dwFlags is not supported\n");
2230 else
2232 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2233 trace("%s\n", date_fmt_buf);
2234 /* test the 1st enumerated format */
2235 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2236 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2237 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2238 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2241 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2242 date_fmt_buf[0] = 0;
2243 SetLastError(0xdeadbeef);
2244 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2245 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2247 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2249 else
2251 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2252 trace("%s\n", date_fmt_buf);
2253 /* test the 1st enumerated format */
2254 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2255 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2256 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2257 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2260 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2261 date_fmt_buf[0] = 0;
2262 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2263 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2264 trace("%s\n", date_fmt_buf);
2265 /* test the 1st enumerated format */
2266 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2267 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2268 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2269 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2271 trace("EnumDateFormatsA DATE_LONGDATE\n");
2272 date_fmt_buf[0] = 0;
2273 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2274 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2275 trace("%s\n", date_fmt_buf);
2276 /* test the 1st enumerated format */
2277 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2278 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2279 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2280 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2282 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2283 date_fmt_buf[0] = 0;
2284 SetLastError(0xdeadbeef);
2285 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2286 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2288 skip("DATE_YEARMONTH is only present on W2K and later\n");
2289 return;
2291 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2292 trace("%s\n", date_fmt_buf);
2293 /* test the 1st enumerated format */
2294 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2295 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2296 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2297 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2300 static void test_EnumTimeFormatsA(void)
2302 char *p, buf[256];
2303 BOOL ret;
2304 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2306 trace("EnumTimeFormatsA 0\n");
2307 date_fmt_buf[0] = 0;
2308 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2309 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2310 trace("%s\n", date_fmt_buf);
2311 /* test the 1st enumerated format */
2312 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2313 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2314 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2315 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2317 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2318 date_fmt_buf[0] = 0;
2319 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2320 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2321 trace("%s\n", date_fmt_buf);
2322 /* test the 1st enumerated format */
2323 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2324 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2325 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2326 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2329 static void test_GetCPInfo(void)
2331 BOOL ret;
2332 CPINFO cpinfo;
2334 SetLastError(0xdeadbeef);
2335 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2336 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2337 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2338 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2340 SetLastError(0xdeadbeef);
2341 ret = GetCPInfo(CP_UTF7, &cpinfo);
2342 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2344 skip("Codepage CP_UTF7 is not installed/available\n");
2346 else
2348 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2349 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2350 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2351 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2352 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2353 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2356 SetLastError(0xdeadbeef);
2357 ret = GetCPInfo(CP_UTF8, &cpinfo);
2358 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2360 skip("Codepage CP_UTF8 is not installed/available\n");
2362 else
2364 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2365 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2366 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2367 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2368 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2369 ok(cpinfo.MaxCharSize == 4, "expected 4, got 0x%x\n", cpinfo.MaxCharSize);
2373 START_TEST(locale)
2375 InitFunctionPointers();
2377 test_EnumTimeFormatsA();
2378 test_EnumDateFormatsA();
2379 test_GetLocaleInfoA();
2380 test_GetTimeFormatA();
2381 test_GetDateFormatA();
2382 test_GetDateFormatW();
2383 test_GetCurrencyFormatA(); /* Also tests the W version */
2384 test_GetNumberFormatA(); /* Also tests the W version */
2385 test_CompareStringA();
2386 test_LCMapStringA();
2387 test_LCMapStringW();
2388 test_FoldStringA();
2389 test_FoldStringW();
2390 test_ConvertDefaultLocale();
2391 test_EnumSystemLanguageGroupsA();
2392 test_EnumLanguageGroupLocalesA();
2393 test_SetLocaleInfoA();
2394 test_EnumUILanguageA();
2395 test_GetCPInfo();
2396 /* this requires collation table patch to make it MS compatible */
2397 if (0) test_sorting();