push 73336d9f381967eae40f391d78198b916ed9848d
[wine/hacks.git] / dlls / kernel32 / tests / locale.c
blob863134b37ad4dec2b4e5ef790b70da4abba11a27
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"); /* Insufficent 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, 0x10, "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 == 3, "a\\0b vs a expected 3, got %d\n", ret);
1007 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1008 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1011 static void test_LCMapStringA(void)
1013 int ret, ret2;
1014 char buf[256], buf2[256];
1015 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1016 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1017 static const char symbols_stripped[] = "justateststring1";
1019 SetLastError(0xdeadbeef);
1020 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1021 lower_case, -1, buf, sizeof(buf));
1022 ok(ret == lstrlenA(lower_case) + 1,
1023 "ret %d, error %d, expected value %d\n",
1024 ret, GetLastError(), lstrlenA(lower_case) + 1);
1025 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1027 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1028 upper_case, -1, buf, sizeof(buf));
1029 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1030 ok(GetLastError() == ERROR_INVALID_FLAGS,
1031 "unexpected error code %d\n", GetLastError());
1033 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1034 upper_case, -1, buf, sizeof(buf));
1035 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1036 ok(GetLastError() == ERROR_INVALID_FLAGS,
1037 "unexpected error code %d\n", GetLastError());
1039 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1040 upper_case, -1, buf, sizeof(buf));
1041 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1042 ok(GetLastError() == ERROR_INVALID_FLAGS,
1043 "unexpected error code %d\n", GetLastError());
1045 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1046 upper_case, -1, buf, sizeof(buf));
1047 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1048 ok(GetLastError() == ERROR_INVALID_FLAGS,
1049 "unexpected error code %d\n", GetLastError());
1051 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1052 SetLastError(0xdeadbeef);
1053 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1054 upper_case, -1, buf, sizeof(buf));
1055 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1056 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1058 /* test LCMAP_LOWERCASE */
1059 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1060 upper_case, -1, buf, sizeof(buf));
1061 ok(ret == lstrlenA(upper_case) + 1,
1062 "ret %d, error %d, expected value %d\n",
1063 ret, GetLastError(), lstrlenA(upper_case) + 1);
1064 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1066 /* test LCMAP_UPPERCASE */
1067 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1068 lower_case, -1, buf, sizeof(buf));
1069 ok(ret == lstrlenA(lower_case) + 1,
1070 "ret %d, error %d, expected value %d\n",
1071 ret, GetLastError(), lstrlenA(lower_case) + 1);
1072 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1074 /* test buffer overflow */
1075 SetLastError(0xdeadbeef);
1076 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1077 lower_case, -1, buf, 4);
1078 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1079 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1081 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1082 lstrcpyA(buf, lower_case);
1083 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1084 buf, -1, buf, sizeof(buf));
1085 if (!ret) /* Win9x */
1086 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1087 else
1089 ok(ret == lstrlenA(lower_case) + 1,
1090 "ret %d, error %d, expected value %d\n",
1091 ret, GetLastError(), lstrlenA(lower_case) + 1);
1092 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1094 lstrcpyA(buf, upper_case);
1095 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1096 buf, -1, buf, sizeof(buf));
1097 if (!ret) /* Win9x */
1098 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1099 else
1101 ok(ret == lstrlenA(upper_case) + 1,
1102 "ret %d, error %d, expected value %d\n",
1103 ret, GetLastError(), lstrlenA(lower_case) + 1);
1104 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1107 /* otherwise src == dst should fail */
1108 SetLastError(0xdeadbeef);
1109 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1110 buf, 10, buf, sizeof(buf));
1111 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1112 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1113 "unexpected error code %d\n", GetLastError());
1114 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1116 /* test whether '\0' is always appended */
1117 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1118 upper_case, -1, buf, sizeof(buf));
1119 ok(ret, "LCMapStringA must succeed\n");
1120 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1121 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1122 ok(ret, "LCMapStringA must succeed\n");
1123 ok(ret == ret2, "lengths of sort keys must be equal\n");
1124 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1126 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1127 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1128 upper_case, -1, buf, sizeof(buf));
1129 ok(ret, "LCMapStringA must succeed\n");
1130 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1131 lower_case, -1, buf2, sizeof(buf2));
1132 ok(ret2, "LCMapStringA must succeed\n");
1133 ok(ret == ret2, "lengths of sort keys must be equal\n");
1134 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1136 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1137 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1138 lower_case, -1, buf, sizeof(buf));
1139 ok(ret, "LCMapStringA must succeed\n");
1140 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1141 lower_case, -1, buf2, sizeof(buf2));
1142 ok(ret2, "LCMapStringA must succeed\n");
1143 ok(ret == ret2, "lengths of sort keys must be equal\n");
1144 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1146 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1147 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1148 lower_case, -1, buf, sizeof(buf));
1149 ok(ret, "LCMapStringA must succeed\n");
1150 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1151 symbols_stripped, -1, buf2, sizeof(buf2));
1152 ok(ret2, "LCMapStringA must succeed\n");
1153 ok(ret == ret2, "lengths of sort keys must be equal\n");
1154 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1156 /* test NORM_IGNORENONSPACE */
1157 lstrcpyA(buf, "foo");
1158 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1159 lower_case, -1, buf, sizeof(buf));
1160 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1161 lstrlenA(lower_case) + 1, ret);
1162 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1164 /* test NORM_IGNORESYMBOLS */
1165 lstrcpyA(buf, "foo");
1166 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1167 lower_case, -1, buf, sizeof(buf));
1168 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1169 lstrlenA(symbols_stripped) + 1, ret);
1170 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1172 /* test srclen = 0 */
1173 SetLastError(0xdeadbeef);
1174 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1175 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1176 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1177 "unexpected error code %d\n", GetLastError());
1180 static void test_LCMapStringW(void)
1182 int ret, ret2;
1183 WCHAR buf[256], buf2[256];
1184 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1185 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};
1186 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};
1187 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1188 static const WCHAR fooW[] = {'f','o','o',0};
1190 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1191 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1192 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1194 trace("Skipping LCMapStringW tests on Win9x\n");
1195 return;
1197 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1198 ok(GetLastError() == ERROR_INVALID_FLAGS,
1199 "unexpected error code %d\n", GetLastError());
1201 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1202 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1203 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1204 ok(GetLastError() == ERROR_INVALID_FLAGS,
1205 "unexpected error code %d\n", GetLastError());
1207 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1208 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1209 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1210 ok(GetLastError() == ERROR_INVALID_FLAGS,
1211 "unexpected error code %d\n", GetLastError());
1213 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1214 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1215 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1216 ok(GetLastError() == ERROR_INVALID_FLAGS,
1217 "unexpected error code %d\n", GetLastError());
1219 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1220 SetLastError(0xdeadbeef);
1221 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1222 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1223 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1224 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1226 /* test LCMAP_LOWERCASE */
1227 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1228 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1229 ok(ret == lstrlenW(upper_case) + 1,
1230 "ret %d, error %d, expected value %d\n",
1231 ret, GetLastError(), lstrlenW(upper_case) + 1);
1232 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1234 /* test LCMAP_UPPERCASE */
1235 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1236 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1237 ok(ret == lstrlenW(lower_case) + 1,
1238 "ret %d, error %d, expected value %d\n",
1239 ret, GetLastError(), lstrlenW(lower_case) + 1);
1240 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1242 /* test buffer overflow */
1243 SetLastError(0xdeadbeef);
1244 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1245 lower_case, -1, buf, 4);
1246 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1247 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1249 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1250 lstrcpyW(buf, lower_case);
1251 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1252 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1253 ok(ret == lstrlenW(lower_case) + 1,
1254 "ret %d, error %d, expected value %d\n",
1255 ret, GetLastError(), lstrlenW(lower_case) + 1);
1256 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1258 lstrcpyW(buf, upper_case);
1259 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1260 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1261 ok(ret == lstrlenW(upper_case) + 1,
1262 "ret %d, error %d, expected value %d\n",
1263 ret, GetLastError(), lstrlenW(lower_case) + 1);
1264 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1266 /* otherwise src == dst should fail */
1267 SetLastError(0xdeadbeef);
1268 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1269 buf, 10, buf, sizeof(buf));
1270 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1271 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1272 "unexpected error code %d\n", GetLastError());
1273 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1275 /* test whether '\0' is always appended */
1276 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1277 upper_case, -1, buf, sizeof(buf));
1278 ok(ret, "LCMapStringW must succeed\n");
1279 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1280 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1281 ok(ret, "LCMapStringW must succeed\n");
1282 ok(ret == ret2, "lengths of sort keys must be equal\n");
1283 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1285 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1286 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1287 upper_case, -1, buf, sizeof(buf));
1288 ok(ret, "LCMapStringW must succeed\n");
1289 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1290 lower_case, -1, buf2, sizeof(buf2));
1291 ok(ret2, "LCMapStringW must succeed\n");
1292 ok(ret == ret2, "lengths of sort keys must be equal\n");
1293 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1295 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1296 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1297 lower_case, -1, buf, sizeof(buf));
1298 ok(ret, "LCMapStringW must succeed\n");
1299 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1300 lower_case, -1, buf2, sizeof(buf2));
1301 ok(ret2, "LCMapStringW must succeed\n");
1302 ok(ret == ret2, "lengths of sort keys must be equal\n");
1303 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1305 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1306 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1307 lower_case, -1, buf, sizeof(buf));
1308 ok(ret, "LCMapStringW must succeed\n");
1309 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1310 symbols_stripped, -1, buf2, sizeof(buf2));
1311 ok(ret2, "LCMapStringW must succeed\n");
1312 ok(ret == ret2, "lengths of sort keys must be equal\n");
1313 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1315 /* test NORM_IGNORENONSPACE */
1316 lstrcpyW(buf, fooW);
1317 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1318 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1319 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1320 lstrlenW(lower_case) + 1, ret);
1321 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1323 /* test NORM_IGNORESYMBOLS */
1324 lstrcpyW(buf, fooW);
1325 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1326 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1327 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1328 lstrlenW(symbols_stripped) + 1, ret);
1329 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1331 /* test srclen = 0 */
1332 SetLastError(0xdeadbeef);
1333 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1334 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1335 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1336 "unexpected error code %d\n", GetLastError());
1339 /* this requires collation table patch to make it MS compatible */
1340 const char *strings_sorted[] =
1342 "'",
1343 "-",
1344 "!",
1345 "\"",
1346 ".",
1347 ":",
1348 "\\",
1349 "_",
1350 "`",
1351 "{",
1352 "}",
1353 "+",
1354 "0",
1355 "1",
1356 "2",
1357 "3",
1358 "4",
1359 "5",
1360 "6",
1361 "7",
1362 "8",
1363 "9",
1364 "a",
1365 "A",
1366 "b",
1367 "B",
1368 "c",
1372 const char *strings[] =
1374 "C",
1375 "\"",
1376 "9",
1377 "'",
1378 "}",
1379 "-",
1380 "7",
1381 "+",
1382 "`",
1383 "1",
1384 "a",
1385 "5",
1386 "\\",
1387 "8",
1388 "B",
1389 "3",
1390 "_",
1391 "6",
1392 "{",
1393 "2",
1394 "c",
1395 "4",
1396 "!",
1397 "0",
1398 "A",
1399 ":",
1400 "b",
1404 static int compare_string1(const void *e1, const void *e2)
1406 const char *s1 = *(const char *const *)e1;
1407 const char *s2 = *(const char *const *)e2;
1409 return lstrcmpA(s1, s2);
1412 static int compare_string2(const void *e1, const void *e2)
1414 const char *s1 = *(const char *const *)e1;
1415 const char *s2 = *(const char *const *)e2;
1417 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1420 static int compare_string3(const void *e1, const void *e2)
1422 const char *s1 = *(const char *const *)e1;
1423 const char *s2 = *(const char *const *)e2;
1424 char key1[256], key2[256];
1426 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1427 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1428 return strcmp(key1, key2);
1431 static void test_sorting(void)
1433 char buf[256];
1434 char **str_buf = (char **)buf;
1435 int i;
1437 assert(sizeof(buf) >= sizeof(strings));
1439 /* 1. sort using lstrcmpA */
1440 memcpy(buf, strings, sizeof(strings));
1441 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1442 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1444 ok(!strcmp(strings_sorted[i], str_buf[i]),
1445 "qsort using lstrcmpA failed for element %d\n", i);
1447 /* 2. sort using CompareStringA */
1448 memcpy(buf, strings, sizeof(strings));
1449 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1450 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1452 ok(!strcmp(strings_sorted[i], str_buf[i]),
1453 "qsort using CompareStringA failed for element %d\n", i);
1455 /* 3. sort using sort keys */
1456 memcpy(buf, strings, sizeof(strings));
1457 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1458 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1460 ok(!strcmp(strings_sorted[i], str_buf[i]),
1461 "qsort using sort keys failed for element %d\n", i);
1465 static void test_FoldStringA(void)
1467 int ret, i;
1468 char src[256], dst[256];
1469 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1470 static const char digits_dst[] = { '1','2','3','\0' };
1471 static const char composite_src[] =
1473 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1474 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1475 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1476 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1477 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1478 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1479 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1480 0xfb,0xfc,0xfd,0xff,'\0'
1482 static const char composite_dst[] =
1484 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1485 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1486 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1487 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1488 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1489 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1490 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1491 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1492 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1493 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1494 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1495 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1496 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1497 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1498 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1500 static const char ligatures_src[] =
1502 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1504 static const char ligatures_dst[] =
1506 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1509 if (!pFoldStringA)
1510 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1512 /* these tests are locale specific */
1513 if (GetACP() != 1252)
1515 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1516 return;
1519 /* MAP_FOLDDIGITS */
1520 SetLastError(0);
1521 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1522 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1523 return;
1524 EXPECT_LEN(4); EXPECT_VALID;
1525 ok(strcmp(dst, digits_dst) == 0,
1526 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1527 for (i = 1; i < 256; i++)
1529 if (!strchr(digits_src, i))
1531 src[0] = i;
1532 src[1] = '\0';
1533 SetLastError(0);
1534 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1535 EXPECT_LEN(2); EXPECT_VALID;
1536 ok(dst[0] == src[0],
1537 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1541 /* MAP_EXPAND_LIGATURES */
1542 SetLastError(0);
1543 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1544 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1545 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1546 EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
1547 ok(strcmp(dst, ligatures_dst) == 0,
1548 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1549 for (i = 1; i < 256; i++)
1551 if (!strchr(ligatures_src, i))
1553 src[0] = i;
1554 src[1] = '\0';
1555 SetLastError(0);
1556 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1557 EXPECT_LEN(2); EXPECT_VALID;
1558 ok(dst[0] == src[0],
1559 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1564 /* MAP_COMPOSITE */
1565 SetLastError(0);
1566 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1567 EXPECT_VALID;
1568 todo_wine
1570 /* Wine gets close, but doesn't produce quite the same result as native */
1571 EXPECT_LEN(121);
1572 ok(strcmp(dst, composite_dst) == 0,
1573 "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
1576 for (i = 1; i < 256; i++)
1578 if (!strchr(composite_src, i))
1580 src[0] = i;
1581 src[1] = '\0';
1582 SetLastError(0);
1583 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1584 EXPECT_LEN(2); EXPECT_VALID;
1585 ok(dst[0] == src[0],
1586 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1587 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1591 /* MAP_FOLDCZONE */
1592 for (i = 1; i < 256; i++)
1594 src[0] = i;
1595 src[1] = '\0';
1596 SetLastError(0);
1597 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1598 EXPECT_LEN(2); EXPECT_VALID;
1599 ok(src[0] == dst[0],
1600 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1601 (unsigned char)src[0], (unsigned char)dst[0]);
1604 /* MAP_PRECOMPOSED */
1605 for (i = 1; i < 256; i++)
1607 src[0] = i;
1608 src[1] = '\0';
1609 SetLastError(0);
1610 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1611 EXPECT_LEN(2); EXPECT_VALID;
1612 ok(src[0] == dst[0],
1613 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1614 (unsigned char)src[0], (unsigned char)dst[0]);
1618 static void test_FoldStringW(void)
1620 int ret;
1621 unsigned int i, j;
1622 WCHAR src[256], dst[256], ch, prev_ch = 1;
1623 static const DWORD badFlags[] =
1626 MAP_PRECOMPOSED|MAP_COMPOSITE,
1627 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1628 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1630 /* Ranges of digits 0-9 : Must be sorted! */
1631 static const WCHAR digitRanges[] =
1633 0x0030, /* '0'-'9' */
1634 0x0660, /* Eastern Arabic */
1635 0x06F0, /* Arabic - Hindu */
1636 0x0966, /* Devengari */
1637 0x09E6, /* Bengalii */
1638 0x0A66, /* Gurmukhi */
1639 0x0AE6, /* Gujarati */
1640 0x0B66, /* Oriya */
1641 0x0BE6, /* Tamil - No 0 */
1642 0x0C66, /* Telugu */
1643 0x0CE6, /* Kannada */
1644 0x0D66, /* Maylayalam */
1645 0x0E50, /* Thai */
1646 0x0ED0, /* Laos */
1647 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1648 0x2080, /* Subscript */
1649 0x245F, /* Circled - 0 is out of sequence */
1650 0x2473, /* Bracketed */
1651 0x2487, /* Full stop */
1652 0x2775, /* Inverted circled - No 0 */
1653 0x277F, /* Patterned circled - No 0 */
1654 0x2789, /* Inverted Patterned circled - No 0 */
1655 0xff10, /* Pliene chasse (?) */
1656 0xffff /* Terminator */
1658 /* Digits which are represented, but out of sequence */
1659 static const WCHAR outOfSequenceDigits[] =
1661 0xB9, /* Superscript 1 */
1662 0xB2, /* Superscript 2 */
1663 0xB3, /* Superscript 3 */
1664 0x24EA, /* Circled 0 */
1665 '\0' /* Terminator */
1667 /* Digits in digitRanges for which no representation is available */
1668 static const WCHAR noDigitAvailable[] =
1670 0x0BE6, /* No Tamil 0 */
1671 0x2473, /* No Bracketed 0 */
1672 0x2487, /* No 0 Full stop */
1673 0x2775, /* No inverted circled 0 */
1674 0x277F, /* No patterned circled */
1675 0x2789, /* No inverted Patterned circled */
1676 '\0' /* Terminator */
1678 /* Compatibility conversion results */
1679 static const WCHAR compat_F900_FA2F[256+48] =
1681 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
1682 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
1683 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
1684 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
1685 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
1686 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
1687 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
1688 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
1689 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
1690 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
1691 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
1692 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
1693 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
1694 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
1695 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
1696 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
1697 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
1698 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
1699 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
1700 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
1701 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
1702 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
1703 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
1704 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
1705 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
1706 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
1707 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
1708 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
1709 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
1710 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
1711 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
1712 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
1713 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
1714 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
1715 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
1716 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
1717 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
1718 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
1720 static const WCHAR compat_FE30_FEF7[200] =
1722 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
1723 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
1724 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
1725 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
1726 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
1727 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
1728 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
1729 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
1730 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
1731 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
1732 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
1733 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
1734 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
1735 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
1736 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
1737 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
1738 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
1739 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
1740 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
1741 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
1742 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
1743 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
1744 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
1745 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
1746 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
1748 static const WCHAR compat_FF00_FFEF[240] =
1750 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1751 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1752 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1753 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
1754 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1755 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1756 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1757 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
1758 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1759 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1760 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1761 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1762 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
1763 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
1764 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
1765 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
1766 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
1767 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
1768 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
1769 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
1770 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
1771 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
1772 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
1773 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
1774 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
1775 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
1776 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
1777 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
1778 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
1779 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
1781 static const WCHAR ligatures_src[] =
1783 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1784 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1785 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1786 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
1787 0xfb04, 0xfb05, 0xfb06, '\0'
1789 static const WCHAR ligatures_dst[] =
1791 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
1792 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
1793 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
1794 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
1795 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
1798 if (!pFoldStringW)
1800 skip("FoldStringW is not available\n");
1801 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1804 /* Invalid flag combinations */
1805 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1807 src[0] = dst[0] = '\0';
1808 SetLastError(0);
1809 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1810 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1812 skip("FoldStringW is not implemented\n");
1813 return;
1815 EXPECT_LEN(0); EXPECT_FLAGS;
1818 /* src & dst cannot be the same */
1819 SetLastError(0);
1820 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
1821 EXPECT_LEN(0); EXPECT_INVALID;
1823 /* src can't be NULL */
1824 SetLastError(0);
1825 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1826 EXPECT_LEN(0); EXPECT_INVALID;
1828 /* srclen can't be 0 */
1829 SetLastError(0);
1830 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1831 EXPECT_LEN(0); EXPECT_INVALID;
1833 /* dstlen can't be < 0 */
1834 SetLastError(0);
1835 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1836 EXPECT_LEN(0); EXPECT_INVALID;
1838 /* Ret includes terminating NUL which is appended if srclen = -1 */
1839 SetLastError(0);
1840 src[0] = 'A';
1841 src[1] = '\0';
1842 dst[0] = '\0';
1843 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1844 EXPECT_LEN(2); EXPECT_VALID;
1845 ok(dst[0] == 'A' && dst[1] == '\0',
1846 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
1847 'A', '\0', ret, dst[0], dst[1], GetLastError());
1849 /* If size is given, result is not NUL terminated */
1850 SetLastError(0);
1851 src[0] = 'A';
1852 src[1] = 'A';
1853 dst[0] = 'X';
1854 dst[1] = 'X';
1855 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
1856 EXPECT_LEN(1); EXPECT_VALID;
1857 ok(dst[0] == 'A' && dst[1] == 'X',
1858 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
1859 'A','X', ret, dst[0], dst[1], GetLastError());
1861 /* MAP_FOLDDIGITS */
1862 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1864 /* Check everything before this range */
1865 for (ch = prev_ch; ch < digitRanges[j]; ch++)
1867 SetLastError(0);
1868 src[0] = ch;
1869 src[1] = dst[0] = '\0';
1870 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1871 EXPECT_LEN(2); EXPECT_VALID;
1873 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
1874 /* Wine (correctly) maps all Unicode 4.0+ digits */
1875 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
1876 (ch >= 0x1369 && ch <= 0x1371),
1877 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
1880 if (digitRanges[j] == 0xffff)
1881 break; /* Finished the whole code point space */
1883 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1885 WCHAR c;
1887 /* Map out of sequence characters */
1888 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
1889 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
1890 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
1891 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
1892 else c = ch;
1893 SetLastError(0);
1894 src[0] = c;
1895 src[1] = dst[0] = '\0';
1896 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1897 EXPECT_LEN(2); EXPECT_VALID;
1899 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
1900 strchrW(noDigitAvailable, c),
1901 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
1902 ch, '0' + digitRanges[j] - ch, dst[0]);
1904 prev_ch = ch;
1907 /* MAP_FOLDCZONE */
1908 for (ch = 1; ch <0xffff; ch++)
1910 WCHAR expected = 0;
1912 if (ch >= 0xF900 && ch <= 0xFA2F)
1913 expected = compat_F900_FA2F[ch - 0xF900];
1914 else if (ch >= 0xFE30 && ch <= 0xFEF7)
1915 expected = compat_FE30_FEF7[ch - 0xFE30];
1916 else if (ch >= 0xFF00 && ch <= 0xFFEF)
1917 expected = compat_FF00_FFEF[ch - 0xFF00];
1919 if (!expected)
1920 expected = ch;
1922 SetLastError(0);
1923 src[0] = ch;
1924 src[1] = dst[0] = '\0';
1925 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1926 EXPECT_LEN(2); EXPECT_VALID;
1927 ok(dst[0] == expected ||
1928 /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
1929 /* FIXME: But they should be re-checked */
1930 ch == 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 ||
1931 ch == 0xf9f1 ||
1932 (0xfa0c <= ch && ch <= 0xfa6a) ||
1933 (0xfa70 <= ch && ch <= 0xfad9) ||
1934 ch == 0xfe47 || ch == 0xfe48 || ch == 0xfe68 ||
1935 (0xfe70 <= ch && ch <= 0xfe7f) ||
1936 ch == 0xff3c || ch == 0xff5f || ch == 0xff60 ||
1937 ch == 0xff9e || ch == 0xff9f,
1938 "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
1939 ch, ch, expected, dst[0]);
1942 /* MAP_EXPAND_LIGATURES */
1943 SetLastError(0);
1944 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1945 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1946 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1947 EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
1948 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
1949 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
1950 for (i = 1; i <= 0xffff; i++)
1952 if (!strchrW(ligatures_src, i))
1954 src[0] = i;
1955 src[1] = '\0';
1956 SetLastError(0);
1957 ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1958 EXPECT_LEN(2); EXPECT_VALID;
1959 ok(dst[0] == src[0],
1960 "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n",
1961 i, src[0], dst[0]);
1966 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1971 #define LCID_OK(l) \
1972 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
1973 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
1974 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
1975 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
1976 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
1978 static void test_ConvertDefaultLocale(void)
1980 LCID lcid;
1982 /* Doesn't change lcid, even if non default sublang/sort used */
1983 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
1984 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
1985 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
1986 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
1988 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
1989 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
1990 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
1991 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
1992 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
1993 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
1994 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
1996 /* Invariant language is not treated specially */
1997 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
1998 LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
1999 MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
2001 /* User/system default languages alone are not mapped */
2002 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2003 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2005 /* Default lcids */
2006 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2007 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2008 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2011 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2012 DWORD dwFlags, LONG_PTR lParam)
2014 trace("%08x, %s, %s, %08x, %08lx\n",
2015 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2017 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2018 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2020 /* If lParam is one, we are calling with flags defaulted from 0 */
2021 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2022 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2024 return TRUE;
2027 static void test_EnumSystemLanguageGroupsA(void)
2029 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2030 return;
2032 /* No enumeration proc */
2033 SetLastError(0);
2034 pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2035 EXPECT_INVALID;
2037 /* Invalid flags */
2038 SetLastError(0);
2039 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2040 EXPECT_FLAGS;
2042 /* No flags - defaults to LGRPID_INSTALLED */
2043 SetLastError(0);
2044 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2045 EXPECT_LASTERROR_0;
2047 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2048 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2052 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2053 LONG_PTR lParam)
2055 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2057 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2058 "Enumerated grp %d not valid\n", lgrpid);
2059 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2060 "Enumerated grp locale %d not valid\n", lcid);
2061 return TRUE;
2064 static void test_EnumLanguageGroupLocalesA(void)
2066 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2067 return;
2069 /* No enumeration proc */
2070 SetLastError(0);
2071 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2072 EXPECT_INVALID;
2074 /* lgrpid too small */
2075 SetLastError(0);
2076 pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2077 EXPECT_INVALID;
2079 /* lgrpid too big */
2080 SetLastError(0);
2081 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2082 EXPECT_INVALID;
2084 /* dwFlags is reserved */
2085 SetLastError(0);
2086 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2087 EXPECT_INVALID;
2089 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2092 static void test_SetLocaleInfoA(void)
2094 BOOL bRet;
2095 LCID lcid = GetUserDefaultLCID();
2097 /* Null data */
2098 SetLastError(0);
2099 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2100 EXPECT_INVALID;
2102 /* IDATE */
2103 SetLastError(0);
2104 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2105 EXPECT_FLAGS;
2107 /* ILDATE */
2108 SetLastError(0);
2109 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2110 EXPECT_FLAGS;
2113 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2115 trace("%s %08lx\n", value, lParam);
2116 return(TRUE);
2119 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2121 ok(!enumCount, "callback called again unexpected\n");
2122 enumCount++;
2123 return(FALSE);
2126 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2128 ok(0,"callback called unexpected\n");
2129 return(FALSE);
2132 static void test_EnumUILanguageA(void)
2134 BOOL ret;
2135 if (!pEnumUILanguagesA) {
2136 trace("EnumUILanguagesA is not available on Win9x\n");
2137 return;
2140 SetLastError(ERROR_SUCCESS);
2141 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2142 EXPECT_TRUE; EXPECT_VALID;
2144 enumCount = 0;
2145 SetLastError(ERROR_SUCCESS);
2146 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2147 EXPECT_TRUE; EXPECT_VALID;
2149 SetLastError(ERROR_SUCCESS);
2150 ret = pEnumUILanguagesA(NULL, 0, 0);
2151 EXPECT_FALSE; EXPECT_INVALID;
2153 SetLastError(ERROR_SUCCESS);
2154 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2155 EXPECT_FALSE; EXPECT_FLAGS;
2157 SetLastError(ERROR_SUCCESS);
2158 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2159 EXPECT_FALSE; EXPECT_INVALID;
2162 static char date_fmt_buf[1024];
2164 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2166 lstrcatA(date_fmt_buf, fmt);
2167 lstrcatA(date_fmt_buf, "\n");
2168 return TRUE;
2171 static void test_EnumDateFormatsA(void)
2173 char *p, buf[256];
2174 BOOL ret;
2175 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2177 trace("EnumDateFormatsA 0\n");
2178 date_fmt_buf[0] = 0;
2179 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2180 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2181 trace("%s\n", date_fmt_buf);
2182 /* test the 1st enumerated format */
2183 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2184 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2185 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2186 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2188 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2189 date_fmt_buf[0] = 0;
2190 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2191 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2192 trace("%s\n", date_fmt_buf);
2193 /* test the 1st enumerated format */
2194 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2195 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2196 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2197 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2199 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2200 date_fmt_buf[0] = 0;
2201 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2202 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2203 trace("%s\n", date_fmt_buf);
2204 /* test the 1st enumerated format */
2205 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2206 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2207 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2208 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2210 trace("EnumDateFormatsA DATE_LONGDATE\n");
2211 date_fmt_buf[0] = 0;
2212 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2213 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2214 trace("%s\n", date_fmt_buf);
2215 /* test the 1st enumerated format */
2216 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2217 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2218 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2219 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2221 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2222 date_fmt_buf[0] = 0;
2223 SetLastError(0xdeadbeef);
2224 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2225 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2227 skip("DATE_YEARMONTH is only present on W2K and later\n");
2228 return;
2230 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2231 trace("%s\n", date_fmt_buf);
2232 /* test the 1st enumerated format */
2233 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2234 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2235 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2236 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2239 static void test_EnumTimeFormatsA(void)
2241 char *p, buf[256];
2242 BOOL ret;
2243 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2245 trace("EnumTimeFormatsA 0\n");
2246 date_fmt_buf[0] = 0;
2247 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2248 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2249 trace("%s\n", date_fmt_buf);
2250 /* test the 1st enumerated format */
2251 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2252 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2253 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2254 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2256 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2257 date_fmt_buf[0] = 0;
2258 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2259 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2260 trace("%s\n", date_fmt_buf);
2261 /* test the 1st enumerated format */
2262 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2263 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2264 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2265 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2268 static void test_GetCPInfo(void)
2270 BOOL ret;
2271 CPINFO cpinfo;
2273 SetLastError(0xdeadbeef);
2274 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2275 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2276 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2277 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2279 SetLastError(0xdeadbeef);
2280 ret = GetCPInfo(CP_UTF7, &cpinfo);
2281 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2282 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2283 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2284 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2285 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2286 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2288 SetLastError(0xdeadbeef);
2289 ret = GetCPInfo(CP_UTF8, &cpinfo);
2290 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2291 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2292 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2293 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2294 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2295 ok(cpinfo.MaxCharSize == 4, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2298 START_TEST(locale)
2300 InitFunctionPointers();
2302 test_EnumTimeFormatsA();
2303 test_EnumDateFormatsA();
2304 test_GetLocaleInfoA();
2305 test_GetTimeFormatA();
2306 test_GetDateFormatA();
2307 test_GetDateFormatW();
2308 test_GetCurrencyFormatA(); /* Also tests the W version */
2309 test_GetNumberFormatA(); /* Also tests the W version */
2310 test_CompareStringA();
2311 test_LCMapStringA();
2312 test_LCMapStringW();
2313 test_FoldStringA();
2314 test_FoldStringW();
2315 test_ConvertDefaultLocale();
2316 test_EnumSystemLanguageGroupsA();
2317 test_EnumLanguageGroupLocalesA();
2318 test_SetLocaleInfoA();
2319 test_EnumUILanguageA();
2320 test_GetCPInfo();
2321 /* this requires collation table patch to make it MS compatible */
2322 if (0) test_sorting();