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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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.
32 #include "wine/test.h"
38 static inline unsigned int strlenW( const WCHAR *str )
45 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
48 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
52 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
54 for ( ; *str; str++) if (*str == ch) return (WCHAR *)str;
58 inline static int isdigitW( WCHAR wc )
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,
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,
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");
93 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
94 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
95 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
96 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
97 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
98 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
102 #define eq(received, expected, label, type) \
103 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
104 (label), (received), (expected))
106 #define BUFFER_SIZE 128
107 char GlobalBuffer[BUFFER_SIZE]; /* Buffer used by callback function */
108 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
110 #define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (len), ret)
111 #define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
112 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError())
113 #define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
114 "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError())
115 #define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
116 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
117 #define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
118 GetLastError() == ERROR_INVALID_PARAMETER, \
119 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
120 #define EXPECT_VALID ok(GetLastError() == 0, \
121 "Expected GetLastError() == 0, got %ld\n", GetLastError())
123 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
124 #define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
125 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
126 "Expected '%s', got '%s'\n", Expected, buffer)
128 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
129 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
130 SetLastError(0); buffer[0] = '\0'
131 #define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
132 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
133 #define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n")
134 #define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n")
136 #define NUO LOCALE_NOUSEROVERRIDE
138 static void test_GetLocaleInfoA()
141 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
142 char buffer[BUFFER_SIZE];
144 ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
146 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
147 * partially fill the buffer even if it is too short. See bug 637.
149 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
150 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
151 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
153 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
154 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
155 EXPECT_BUFFER; EXPECT_LEN(0);
156 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
158 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
159 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
160 EXPECT_VALID; EXPECT_LEN(7);
161 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
164 static void test_GetTimeFormatA()
168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
169 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
171 memset(&curtime, 2, sizeof(SYSTEMTIME));
172 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
173 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
174 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
177 curtime.wMinute = 56;
178 curtime.wSecond = 13;
179 curtime.wMilliseconds = 22;
180 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
181 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
182 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
184 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficent buffer */
185 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
186 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
188 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
189 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
190 EXPECT_VALID; EXPECT_LENA;
192 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
193 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
194 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
196 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
197 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
198 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
200 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
201 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
202 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
204 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
205 strcpy(Expected, "8:56 AM");
206 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
207 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
209 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
210 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
211 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
213 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
214 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
215 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
217 STRINGSA("t/tt", "A/AM"); /* AM time marker */
218 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
219 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
222 STRINGSA("t/tt", "P/PM"); /* PM time marker */
223 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
224 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
226 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
227 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
228 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
230 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
231 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
232 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
234 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
235 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
236 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
238 curtime.wHour = 14; /* change this to 14 or 2pm */
241 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 */
242 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
243 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
246 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
247 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
248 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
250 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
251 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
252 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
254 /* try to convert formatting strings with more than two letters
255 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
256 * NOTE: We expect any letter for which there is an upper case value
257 * we should see a replacement. For letters that DO NOT have
258 * upper case values we should see NO REPLACEMENT.
261 curtime.wMinute = 56;
262 curtime.wSecond = 13;
263 curtime.wMilliseconds = 22;
264 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
265 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
266 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
267 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
269 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
270 strcpy(buffer, "text");
271 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
272 EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
274 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
275 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
276 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
277 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
279 STRINGSA("'''", "'"); /* invalid quoted string */
280 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
281 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
283 /* test that msdn suggested single quotation usage works as expected */
284 STRINGSA("''''", "'"); /* single quote mark */
285 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
286 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
288 STRINGSA("''HHHHHH", "08"); /* Normal use */
289 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
290 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
292 /* and test for normal use of the single quotation mark */
293 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
294 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
295 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
297 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
298 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
299 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
301 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
302 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
303 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
306 STRINGSA("'123'tt", ""); /* Invalid time */
307 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
308 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
311 curtime.wMonth = 60; /* Invalid */
312 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
313 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
314 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
317 static void test_GetDateFormatA()
321 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
322 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
324 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
325 STRINGSA("ddd',' MMM dd yy","");
326 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
327 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
329 curtime.wYear = 2002;
332 curtime.wDayOfWeek = 3;
333 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
334 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
335 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
337 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
338 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
339 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
341 curtime.wHour = 36; /* Invalid */
342 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
343 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
344 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
346 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
347 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
348 EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA;
350 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
351 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
352 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
354 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
355 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
356 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
358 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
359 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
360 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
362 /* test for expected DATE_YEARMONTH behavior with null format */
363 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
364 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
365 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
366 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
368 /* Test that using invalid DATE_* flags results in the correct error */
369 /* and return values */
370 STRINGSA("m/d/y", ""); /* Invalid flags */
371 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
372 &curtime, input, buffer, COUNTOF(buffer));
373 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
376 static void test_GetDateFormatW()
380 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
381 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
383 STRINGSW("",""); /* If flags is not zero then format must be NULL */
384 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
385 input, buffer, COUNTOF(buffer));
386 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
388 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW;
390 STRINGSW("",""); /* NULL buffer, len > 0 */
391 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
392 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
394 STRINGSW("",""); /* NULL buffer, len == 0 */
395 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
396 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
398 curtime.wYear = 2002;
401 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
402 curtime.wHour = 65432; /* Invalid */
403 curtime.wMinute = 34512; /* Invalid */
404 curtime.wSecond = 65535; /* Invalid */
405 curtime.wMilliseconds = 12345;
406 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
407 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
408 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
412 #define CY_POS_LEFT 0
413 #define CY_POS_RIGHT 1
414 #define CY_POS_LEFT_SPACE 2
415 #define CY_POS_RIGHT_SPACE 3
417 static void test_GetCurrencyFormatA()
419 static char szDot[] = { '.', '\0' };
420 static char szComma[] = { ',', '\0' };
421 static char szDollar[] = { '$', '\0' };
423 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
424 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
427 memset(&format, 0, sizeof(format));
429 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
430 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
431 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
433 STRINGSA("23,53",""); /* Invalid character --> Error */
434 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
435 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
437 STRINGSA("--",""); /* Double '-' --> Error */
438 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
439 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
441 STRINGSA("0-",""); /* Trailing '-' --> Error */
442 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
443 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
445 STRINGSA("0..",""); /* Double '.' --> Error */
446 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
447 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
449 STRINGSA(" 0.1",""); /* Leading space --> Error */
450 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
451 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
453 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
454 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
455 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
457 STRINGSA("2353",""); /* Format and flags given --> Error */
458 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
459 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
461 STRINGSA("2353",""); /* Invalid format --> Error */
462 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
463 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
465 STRINGSA("2353","$2,353.00"); /* Valid number */
466 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
467 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
469 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
470 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
471 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
473 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
474 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
475 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
477 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
478 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
479 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
481 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
482 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
483 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
485 format.NumDigits = 0; /* No decimal separator */
486 format.LeadingZero = 0;
487 format.Grouping = 0; /* No grouping char */
488 format.NegativeOrder = 0;
489 format.PositiveOrder = CY_POS_LEFT;
490 format.lpDecimalSep = szDot;
491 format.lpThousandSep = szComma;
492 format.lpCurrencySymbol = szDollar;
494 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
495 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
496 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
498 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
499 STRINGSA("2353","$2353.0");
500 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
501 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
503 format.Grouping = 2; /* Group by 100's */
504 STRINGSA("2353","$23,53.0");
505 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
506 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
508 format.LeadingZero = 1; /* Always provide leading zero */
509 STRINGSA(".5","$0.5");
510 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
511 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
513 format.PositiveOrder = CY_POS_RIGHT;
514 STRINGSA("1","1.0$");
515 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
516 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
518 format.PositiveOrder = CY_POS_LEFT_SPACE;
519 STRINGSA("1","$ 1.0");
520 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
521 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
523 format.PositiveOrder = CY_POS_RIGHT_SPACE;
524 STRINGSA("1","1.0 $");
525 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
526 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
528 format.NegativeOrder = 0;
529 STRINGSA("-1","($1.0)");
530 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
531 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
533 format.NegativeOrder = 1;
534 STRINGSA("-1","-$1.0");
535 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
536 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
538 format.NegativeOrder = 2;
539 STRINGSA("-1","$-1.0");
540 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
541 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
543 format.NegativeOrder = 3;
544 STRINGSA("-1","$1.0-");
545 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
546 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
548 format.NegativeOrder = 4;
549 STRINGSA("-1","(1.0$)");
550 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
551 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
553 format.NegativeOrder = 5;
554 STRINGSA("-1","-1.0$");
555 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
556 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
558 format.NegativeOrder = 6;
559 STRINGSA("-1","1.0-$");
560 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
561 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
563 format.NegativeOrder = 7;
564 STRINGSA("-1","1.0$-");
565 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
566 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
568 format.NegativeOrder = 8;
569 STRINGSA("-1","-1.0 $");
570 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
571 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
573 format.NegativeOrder = 9;
574 STRINGSA("-1","-$ 1.0");
575 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
576 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
578 format.NegativeOrder = 10;
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 = 11;
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 = 12;
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 = 13;
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 = 14;
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 = 15;
604 STRINGSA("-1","(1.0 $)");
605 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
606 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
609 #define NEG_PARENS 0 /* "(1.1)" */
610 #define NEG_LEFT 1 /* "-1.1" */
611 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
612 #define NEG_RIGHT 3 /* "1.1-" */
613 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
615 static void test_GetNumberFormatA()
617 static char szDot[] = { '.', '\0' };
618 static char szComma[] = { ',', '\0' };
620 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
621 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
624 memset(&format, 0, sizeof(format));
626 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
627 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
628 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
630 STRINGSA("23,53",""); /* Invalid character --> Error */
631 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
632 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
634 STRINGSA("--",""); /* Double '-' --> Error */
635 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
636 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
638 STRINGSA("0-",""); /* Trailing '-' --> Error */
639 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
640 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
642 STRINGSA("0..",""); /* Double '.' --> Error */
643 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
644 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
646 STRINGSA(" 0.1",""); /* Leading space --> Error */
647 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
648 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
650 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
651 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
652 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
654 STRINGSA("2353",""); /* Format and flags given --> Error */
655 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
656 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
658 STRINGSA("2353",""); /* Invalid format --> Error */
659 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
660 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
662 STRINGSA("2353","2,353.00"); /* Valid number */
663 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
664 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
666 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
667 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
668 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
670 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
671 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
672 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
674 STRINGSA("2353.1","2,353.10"); /* Valid real number */
675 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
676 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
678 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
679 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
680 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
682 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
683 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
684 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
686 format.NumDigits = 0; /* No decimal separator */
687 format.LeadingZero = 0;
688 format.Grouping = 0; /* No grouping char */
689 format.NegativeOrder = 0;
690 format.lpDecimalSep = szDot;
691 format.lpThousandSep = szComma;
693 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
694 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
695 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
697 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
698 STRINGSA("2353","2353.0");
699 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
700 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
702 format.Grouping = 2; /* Group by 100's */
703 STRINGSA("2353","23,53.0");
704 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
705 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
707 format.LeadingZero = 1; /* Always provide leading zero */
708 STRINGSA(".5","0.5");
709 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
710 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
712 format.NegativeOrder = NEG_PARENS;
713 STRINGSA("-1","(1.0)");
714 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
715 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
717 format.NegativeOrder = NEG_LEFT;
718 STRINGSA("-1","-1.0");
719 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
720 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
722 format.NegativeOrder = NEG_LEFT_SPACE;
723 STRINGSA("-1","- 1.0");
724 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
725 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
727 format.NegativeOrder = NEG_RIGHT;
728 STRINGSA("-1","1.0-");
729 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
730 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
732 format.NegativeOrder = NEG_RIGHT_SPACE;
733 STRINGSA("-1","1.0 -");
734 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
735 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
737 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
739 if (IsValidLocale(lcid, 0))
741 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
742 Expected[3] = 160; /* Non breaking space */
743 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
744 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
749 /* Callback function used by TestEnumTimeFormats */
750 static BOOL CALLBACK EnumTimeFormatsProc(char * lpTimeFormatString)
752 trace("%s\n", lpTimeFormatString);
753 strcpy(GlobalBuffer, lpTimeFormatString);
760 void test_EnumTimeFormats()
763 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
765 GlobalBuffer[0] = '\0';
766 ret = EnumTimeFormatsA(EnumTimeFormatsProc, lcid, 0);
767 ok (ret == 1 && !strcmp(GlobalBuffer,"h:mm:ss tt"), "Expected %d '%s'\n", ret, GlobalBuffer);
770 static void test_CompareStringA()
773 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
775 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
776 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
778 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
779 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
781 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
782 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
784 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
785 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
787 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
789 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
790 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
792 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
793 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
795 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
796 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
798 /* test for CompareStringA flags */
799 SetLastError(0xdeadbeef);
800 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1);
801 ok(GetLastError() == ERROR_INVALID_FLAGS,
802 "unexpected error code %ld\n", GetLastError());
803 ok(!ret, "CompareStringA must fail with invalid flag\n");
805 SetLastError(0xdeadbeef);
806 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
807 ok(GetLastError() == 0xdeadbeef, "unexpected error code %ld\n", GetLastError());
808 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
809 /* end of test for CompareStringA flags */
811 ret = lstrcmpA("", "");
812 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
814 ret = lstrcmpA(NULL, NULL);
815 ok (ret == 0, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
817 ret = lstrcmpA("", NULL);
818 ok (ret == 1, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
820 ret = lstrcmpA(NULL, "");
821 ok (ret == -1, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
823 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
824 ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
826 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
827 ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
829 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
830 ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
832 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
833 ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
835 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
836 ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
838 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
839 ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
841 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
842 ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
844 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
845 ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
847 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
848 ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
850 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
851 ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
853 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
854 ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
856 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
857 ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
859 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
860 ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
862 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
863 ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
865 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
866 ok( ret == 3, "a vs { expected 3, got %d\n", ret);
868 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
869 ok( ret == 3, "A vs { expected 3, got %d\n", ret);
871 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
872 ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
874 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
875 ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
877 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
878 ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
880 /* hyphen and apostrophe are treated differently depending on
881 * whether SORT_STRINGSORT specified or not
883 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
884 ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
886 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
887 ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
889 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
890 ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
892 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
893 ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
895 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
896 ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
898 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
899 ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
901 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
902 ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
904 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
905 ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
907 #if 0 /* this requires collation table patch to make it MS compatible */
908 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
909 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
911 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
912 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
914 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
915 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
917 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
918 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
920 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
921 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
923 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
924 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
926 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
927 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
929 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
930 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
932 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
933 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
935 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
936 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
938 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
939 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
941 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
942 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
945 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
946 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
948 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
949 ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
951 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
952 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 2, got %d\n", ret);
954 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
955 ok(ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 2, got %d\n", ret);
958 void test_LCMapStringA(void)
961 char buf[256], buf2[256];
962 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
963 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
964 static const char symbols_stripped[] = "justateststring1";
966 SetLastError(0xdeadbeef);
967 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
968 lower_case, -1, buf, sizeof(buf));
969 ok(ret == lstrlenA(lower_case) + 1,
970 "ret %d, error %ld, expected value %d\n",
971 ret, GetLastError(), lstrlenA(lower_case) + 1);
972 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
974 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
975 upper_case, -1, buf, sizeof(buf));
976 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
977 ok(GetLastError() == ERROR_INVALID_FLAGS,
978 "unexpected error code %ld\n", GetLastError());
980 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
981 upper_case, -1, buf, sizeof(buf));
982 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
983 ok(GetLastError() == ERROR_INVALID_FLAGS,
984 "unexpected error code %ld\n", GetLastError());
986 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
987 upper_case, -1, buf, sizeof(buf));
988 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
989 ok(GetLastError() == ERROR_INVALID_FLAGS,
990 "unexpected error code %ld\n", GetLastError());
992 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
993 upper_case, -1, buf, sizeof(buf));
994 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
995 ok(GetLastError() == ERROR_INVALID_FLAGS,
996 "unexpected error code %ld\n", GetLastError());
998 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
999 SetLastError(0xdeadbeef);
1000 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1001 upper_case, -1, buf, sizeof(buf));
1002 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
1003 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1005 /* test LCMAP_LOWERCASE */
1006 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1007 upper_case, -1, buf, sizeof(buf));
1008 ok(ret == lstrlenA(upper_case) + 1,
1009 "ret %d, error %ld, expected value %d\n",
1010 ret, GetLastError(), lstrlenA(upper_case) + 1);
1011 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1013 /* test LCMAP_UPPERCASE */
1014 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1015 lower_case, -1, buf, sizeof(buf));
1016 ok(ret == lstrlenA(lower_case) + 1,
1017 "ret %d, error %ld, expected value %d\n",
1018 ret, GetLastError(), lstrlenA(lower_case) + 1);
1019 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1021 /* test buffer overflow */
1022 SetLastError(0xdeadbeef);
1023 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1024 lower_case, -1, buf, 4);
1025 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1026 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1028 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1029 lstrcpyA(buf, lower_case);
1030 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1031 buf, -1, buf, sizeof(buf));
1032 if (!ret) /* Win9x */
1033 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1036 ok(ret == lstrlenA(lower_case) + 1,
1037 "ret %d, error %ld, expected value %d\n",
1038 ret, GetLastError(), lstrlenA(lower_case) + 1);
1039 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1041 lstrcpyA(buf, upper_case);
1042 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1043 buf, -1, buf, sizeof(buf));
1044 if (!ret) /* Win9x */
1045 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1048 ok(ret == lstrlenA(upper_case) + 1,
1049 "ret %d, error %ld, expected value %d\n",
1050 ret, GetLastError(), lstrlenA(lower_case) + 1);
1051 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1054 /* otherwise src == dst should fail */
1055 SetLastError(0xdeadbeef);
1056 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1057 buf, 10, buf, sizeof(buf));
1058 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1059 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1060 "unexpected error code %ld\n", GetLastError());
1061 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1063 /* test whether '\0' is always appended */
1064 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1065 upper_case, -1, buf, sizeof(buf));
1066 ok(ret, "LCMapStringA must succeed\n");
1067 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1068 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1069 ok(ret, "LCMapStringA must succeed\n");
1070 ok(ret == ret2, "lengths of sort keys must be equal\n");
1071 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1073 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1074 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1075 upper_case, -1, buf, sizeof(buf));
1076 ok(ret, "LCMapStringA must succeed\n");
1077 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1078 lower_case, -1, buf2, sizeof(buf2));
1079 ok(ret2, "LCMapStringA must succeed\n");
1080 ok(ret == ret2, "lengths of sort keys must be equal\n");
1081 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1083 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1084 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1085 lower_case, -1, buf, sizeof(buf));
1086 ok(ret, "LCMapStringA must succeed\n");
1087 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1088 lower_case, -1, buf2, sizeof(buf2));
1089 ok(ret2, "LCMapStringA must succeed\n");
1090 ok(ret == ret2, "lengths of sort keys must be equal\n");
1091 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1093 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1094 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1095 lower_case, -1, buf, sizeof(buf));
1096 ok(ret, "LCMapStringA must succeed\n");
1097 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1098 symbols_stripped, -1, buf2, sizeof(buf2));
1099 ok(ret2, "LCMapStringA must succeed\n");
1100 ok(ret == ret2, "lengths of sort keys must be equal\n");
1101 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1103 /* test NORM_IGNORENONSPACE */
1104 lstrcpyA(buf, "foo");
1105 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1106 lower_case, -1, buf, sizeof(buf));
1107 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1108 lstrlenA(lower_case) + 1, ret);
1109 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1111 /* test NORM_IGNORESYMBOLS */
1112 lstrcpyA(buf, "foo");
1113 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1114 lower_case, -1, buf, sizeof(buf));
1115 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1116 lstrlenA(symbols_stripped) + 1, ret);
1117 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1119 /* test srclen = 0 */
1120 SetLastError(0xdeadbeef);
1121 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1122 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1123 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1124 "unexpected error code %ld\n", GetLastError());
1127 void test_LCMapStringW(void)
1130 WCHAR buf[256], buf2[256];
1131 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1132 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};
1133 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};
1134 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1135 static const WCHAR fooW[] = {'f','o','o',0};
1137 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1138 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1139 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1141 trace("Skipping LCMapStringW tests on Win9x\n");
1144 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1145 ok(GetLastError() == ERROR_INVALID_FLAGS,
1146 "unexpected error code %ld\n", GetLastError());
1148 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1149 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1150 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1151 ok(GetLastError() == ERROR_INVALID_FLAGS,
1152 "unexpected error code %ld\n", GetLastError());
1154 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1155 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1156 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1157 ok(GetLastError() == ERROR_INVALID_FLAGS,
1158 "unexpected error code %ld\n", GetLastError());
1160 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1161 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1162 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1163 ok(GetLastError() == ERROR_INVALID_FLAGS,
1164 "unexpected error code %ld\n", GetLastError());
1166 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1167 SetLastError(0xdeadbeef);
1168 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1169 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1170 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
1171 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1173 /* test LCMAP_LOWERCASE */
1174 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1175 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1176 ok(ret == lstrlenW(upper_case) + 1,
1177 "ret %d, error %ld, expected value %d\n",
1178 ret, GetLastError(), lstrlenW(upper_case) + 1);
1179 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1181 /* test LCMAP_UPPERCASE */
1182 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1183 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1184 ok(ret == lstrlenW(lower_case) + 1,
1185 "ret %d, error %ld, expected value %d\n",
1186 ret, GetLastError(), lstrlenW(lower_case) + 1);
1187 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1189 /* test buffer overflow */
1190 SetLastError(0xdeadbeef);
1191 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1192 lower_case, -1, buf, 4);
1193 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1194 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1196 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1197 lstrcpyW(buf, lower_case);
1198 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1199 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1200 ok(ret == lstrlenW(lower_case) + 1,
1201 "ret %d, error %ld, expected value %d\n",
1202 ret, GetLastError(), lstrlenW(lower_case) + 1);
1203 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1205 lstrcpyW(buf, upper_case);
1206 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1207 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1208 ok(ret == lstrlenW(upper_case) + 1,
1209 "ret %d, error %ld, expected value %d\n",
1210 ret, GetLastError(), lstrlenW(lower_case) + 1);
1211 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1213 /* otherwise src == dst should fail */
1214 SetLastError(0xdeadbeef);
1215 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1216 buf, 10, buf, sizeof(buf));
1217 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1218 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1219 "unexpected error code %ld\n", GetLastError());
1220 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1222 /* test whether '\0' is always appended */
1223 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1224 upper_case, -1, buf, sizeof(buf));
1225 ok(ret, "LCMapStringW must succeed\n");
1226 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1227 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1228 ok(ret, "LCMapStringW must succeed\n");
1229 ok(ret == ret2, "lengths of sort keys must be equal\n");
1230 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1232 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1233 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1234 upper_case, -1, buf, sizeof(buf));
1235 ok(ret, "LCMapStringW must succeed\n");
1236 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1237 lower_case, -1, buf2, sizeof(buf2));
1238 ok(ret2, "LCMapStringW must succeed\n");
1239 ok(ret == ret2, "lengths of sort keys must be equal\n");
1240 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1242 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1243 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1244 lower_case, -1, buf, sizeof(buf));
1245 ok(ret, "LCMapStringW must succeed\n");
1246 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1247 lower_case, -1, buf2, sizeof(buf2));
1248 ok(ret2, "LCMapStringW must succeed\n");
1249 ok(ret == ret2, "lengths of sort keys must be equal\n");
1250 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1252 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1253 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1254 lower_case, -1, buf, sizeof(buf));
1255 ok(ret, "LCMapStringW must succeed\n");
1256 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1257 symbols_stripped, -1, buf2, sizeof(buf2));
1258 ok(ret2, "LCMapStringW must succeed\n");
1259 ok(ret == ret2, "lengths of sort keys must be equal\n");
1260 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1262 /* test NORM_IGNORENONSPACE */
1263 lstrcpyW(buf, fooW);
1264 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1265 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1266 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1267 lstrlenW(lower_case) + 1, ret);
1268 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1270 /* test NORM_IGNORESYMBOLS */
1271 lstrcpyW(buf, fooW);
1272 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1273 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1274 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1275 lstrlenW(symbols_stripped) + 1, ret);
1276 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1278 /* test srclen = 0 */
1279 SetLastError(0xdeadbeef);
1280 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1281 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1282 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1283 "unexpected error code %ld\n", GetLastError());
1286 #if 0 /* this requires collation table patch to make it MS compatible */
1287 const char *strings_sorted[] =
1319 const char *strings[] =
1351 static int compare_string1(const void *e1, const void *e2)
1353 const char *s1 = *(const char **)e1;
1354 const char *s2 = *(const char **)e2;
1356 return lstrcmpA(s1, s2);
1359 static int compare_string2(const void *e1, const void *e2)
1361 const char *s1 = *(const char **)e1;
1362 const char *s2 = *(const char **)e2;
1364 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1367 static int compare_string3(const void *e1, const void *e2)
1369 const char *s1 = *(const char **)e1;
1370 const char *s2 = *(const char **)e2;
1371 char key1[256], key2[256];
1373 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1374 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1375 return strcmp(key1, key2);
1378 static void test_sorting(void)
1381 char **str_buf = (char **)buf;
1384 assert(sizeof(buf) >= sizeof(strings));
1386 /* 1. sort using lstrcmpA */
1387 memcpy(buf, strings, sizeof(strings));
1388 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1389 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1391 ok(!strcmp(strings_sorted[i], str_buf[i]),
1392 "qsort using lstrcmpA failed for element %d\n", i);
1394 /* 2. sort using CompareStringA */
1395 memcpy(buf, strings, sizeof(strings));
1396 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1397 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1399 ok(!strcmp(strings_sorted[i], str_buf[i]),
1400 "qsort using CompareStringA failed for element %d\n", i);
1402 /* 3. sort using sort keys */
1403 memcpy(buf, strings, sizeof(strings));
1404 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1405 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1407 ok(!strcmp(strings_sorted[i], str_buf[i]),
1408 "qsort using sort keys failed for element %d\n", i);
1413 static void test_FoldStringA(void)
1416 char src[256], dst[256];
1417 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1418 static const char digits_dst[] = { '1','2','3','\0' };
1419 static const char composite_src[] =
1421 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1422 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1423 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1424 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1425 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1426 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1427 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1428 0xfb,0xfc,0xfd,0xff,'\0'
1430 static const char composite_dst[] =
1432 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1433 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1434 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1435 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1436 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1437 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1438 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1439 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1440 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1441 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1442 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1443 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1444 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1445 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1446 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1448 static const char ligatures_src[] =
1450 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1452 static const char ligatures_dst[] =
1454 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1458 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1460 /* these tests are locale specific */
1461 if (GetACP() != 1252)
1463 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1467 /* MAP_FOLDDIGITS */
1469 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1470 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1472 EXPECT_LEN(4); EXPECT_VALID;
1473 ok(strcmp(dst, digits_dst) == 0,
1474 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1475 for (i = 1; i < 256; i++)
1477 if (!strchr(digits_src, i))
1482 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1483 EXPECT_LEN(2); EXPECT_VALID;
1484 ok(dst[0] == src[0],
1485 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1489 /* MAP_EXPAND_LIGATURES */
1491 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1492 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1493 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1494 EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
1495 ok(strcmp(dst, ligatures_dst) == 0,
1496 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1497 for (i = 1; i < 256; i++)
1499 if (!strchr(ligatures_src, i))
1504 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1505 EXPECT_LEN(2); EXPECT_VALID;
1506 ok(dst[0] == src[0],
1507 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1514 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1518 /* Wine gets close, but doesn't produce quite the same result as native */
1520 ok(strcmp(dst, composite_dst) == 0,
1521 "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
1524 for (i = 1; i < 256; i++)
1526 if (!strchr(composite_src, i))
1531 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1532 EXPECT_LEN(2); EXPECT_VALID;
1533 ok(dst[0] == src[0],
1534 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1535 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1540 for (i = 1; i < 256; i++)
1545 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1546 EXPECT_LEN(2); EXPECT_VALID;
1547 ok(src[0] == dst[0],
1548 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1549 (unsigned char)src[0], (unsigned char)dst[0]);
1552 /* MAP_PRECOMPOSED */
1553 for (i = 1; i < 256; i++)
1558 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1559 EXPECT_LEN(2); EXPECT_VALID;
1560 ok(src[0] == dst[0],
1561 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1562 (unsigned char)src[0], (unsigned char)dst[0]);
1566 static void test_FoldStringW(void)
1570 WCHAR src[256], dst[256], ch, prev_ch = 1;
1571 static const DWORD badFlags[] =
1574 MAP_PRECOMPOSED|MAP_COMPOSITE,
1575 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1576 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1578 /* Ranges of digits 0-9 : Must be sorted! */
1579 static const WCHAR digitRanges[] =
1581 0x0030, /* '0'-'9' */
1582 0x0660, /* Eastern Arabic */
1583 0x06F0, /* Arabic - Hindu */
1584 0x0966, /* Devengari */
1585 0x09E6, /* Bengalii */
1586 0x0A66, /* Gurmukhi */
1587 0x0AE6, /* Gujarati */
1589 0x0BE6, /* Tamil - No 0 */
1590 0x0C66, /* Telugu */
1591 0x0CE6, /* Kannada */
1592 0x0D66, /* Maylayalam */
1595 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1596 0x2080, /* Subscript */
1597 0x245F, /* Circled - 0 is out of sequence */
1598 0x2473, /* Bracketed */
1599 0x2487, /* Full stop */
1600 0x2775, /* Inverted circled - No 0 */
1601 0x277F, /* Patterned circled - No 0 */
1602 0x2789, /* Inverted Patterned circled - No 0 */
1603 0xff10, /* Pliene chasse (?) */
1604 0xffff /* Terminator */
1606 /* Digits which are represented, but out of sequence */
1607 static const WCHAR outOfSequenceDigits[] =
1609 0xB9, /* Superscript 1 */
1610 0xB2, /* Superscript 2 */
1611 0xB3, /* Superscript 3 */
1612 0x24EA, /* Circled 0 */
1613 '\0' /* Terminator */
1615 /* Digits in digitRanges for which no representation is available */
1616 static const WCHAR noDigitAvailable[] =
1618 0x0BE6, /* No Tamil 0 */
1619 0x2473, /* No Bracketed 0 */
1620 0x2487, /* No 0 Full stop */
1621 0x2775, /* No inverted circled 0 */
1622 0x277F, /* No patterned circled */
1623 0x2789, /* No inverted Patterned circled */
1624 '\0' /* Terminator */
1626 /* Compatibility conversion results */
1627 static const WCHAR compat_F900_FA2F[256+48] =
1629 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
1630 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
1631 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
1632 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
1633 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
1634 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
1635 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
1636 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
1637 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
1638 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
1639 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
1640 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
1641 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
1642 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
1643 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
1644 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
1645 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
1646 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
1647 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
1648 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
1649 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
1650 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
1651 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
1652 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
1653 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
1654 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
1655 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
1656 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
1657 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
1658 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
1659 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
1660 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
1661 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
1662 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
1663 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
1664 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
1665 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
1666 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
1668 static const WCHAR compat_FE30_FEF7[200] =
1670 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
1671 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
1672 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
1673 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
1674 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
1675 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
1676 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
1677 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
1678 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
1679 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
1680 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
1681 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
1682 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
1683 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
1684 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
1685 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
1686 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
1687 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
1688 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
1689 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
1690 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
1691 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
1692 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
1693 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
1694 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
1696 static const WCHAR compat_FF00_FFEF[240] =
1698 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1699 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1700 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1701 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
1702 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1703 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1704 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1705 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
1706 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1707 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1708 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1709 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1710 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
1711 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
1712 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
1713 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
1714 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
1715 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
1716 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
1717 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
1718 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
1719 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
1720 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
1721 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
1722 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
1723 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
1724 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
1725 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
1726 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
1727 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
1729 static const WCHAR ligatures_src[] =
1731 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1732 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1733 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1734 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
1735 0xfb04, 0xfb05, 0xfb06, '\0'
1737 static const WCHAR ligatures_dst[] =
1739 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
1740 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
1741 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
1742 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
1743 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
1747 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1749 /* Invalid flag combinations */
1750 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1752 src[0] = dst[0] = '\0';
1754 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1755 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1757 EXPECT_LEN(0); EXPECT_FLAGS;
1760 /* src & dst cannot be the same */
1762 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
1763 EXPECT_LEN(0); EXPECT_INVALID;
1765 /* src can't be NULL */
1767 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1768 EXPECT_LEN(0); EXPECT_INVALID;
1770 /* srclen can't be 0 */
1772 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1773 EXPECT_LEN(0); EXPECT_INVALID;
1775 /* dstlen can't be < 0 */
1777 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1778 EXPECT_LEN(0); EXPECT_INVALID;
1780 /* Ret includes terminating NUL which is appended if srclen = -1 */
1785 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1786 EXPECT_LEN(2); EXPECT_VALID;
1787 ok(dst[0] == 'A' && dst[1] == '\0',
1788 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
1789 'A', '\0', ret, dst[0], dst[1], GetLastError());
1791 /* If size is given, result is not NUL terminated */
1797 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
1798 EXPECT_LEN(1); EXPECT_VALID;
1799 ok(dst[0] == 'A' && dst[1] == 'X',
1800 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
1801 'A','X', ret, dst[0], dst[1], GetLastError());
1803 /* MAP_FOLDDIGITS */
1804 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1806 /* Check everything before this range */
1807 for (ch = prev_ch; ch < digitRanges[j]; ch++)
1811 src[1] = dst[0] = '\0';
1812 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1813 EXPECT_LEN(2); EXPECT_VALID;
1815 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
1816 /* Wine (correctly) maps all Unicode 4.0+ digits */
1817 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF,
1818 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
1821 if (digitRanges[j] == 0xffff)
1822 break; /* Finished the whole code point space */
1824 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1828 /* Map out of sequence characters */
1829 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
1830 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
1831 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
1832 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
1836 src[1] = dst[0] = '\0';
1837 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1838 EXPECT_LEN(2); EXPECT_VALID;
1840 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
1841 strchrW(noDigitAvailable, c),
1842 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
1843 ch, '0' + digitRanges[j] - ch, dst[0]);
1849 for (ch = 1; ch <0xffff; ch++)
1853 if (ch >= 0xF900 && ch <= 0xFA2F)
1854 expected = compat_F900_FA2F[ch - 0xF900];
1855 else if (ch >= 0xFE30 && ch <= 0xFEF7)
1856 expected = compat_FE30_FEF7[ch - 0xFE30];
1857 else if (ch >= 0xFF00 && ch <= 0xFFEF)
1858 expected = compat_FF00_FFEF[ch - 0xFF00];
1865 src[1] = dst[0] = '\0';
1866 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1867 EXPECT_LEN(2); EXPECT_VALID;
1868 ok(dst[0] == expected ||
1869 /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
1870 (ch >= 0xFA0D && ch <= 0xFA47) ||
1871 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || ch == 0xf9f1,
1872 "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
1873 ch, ch, expected, dst[0]);
1876 /* MAP_EXPAND_LIGATURES */
1878 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1879 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1880 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1881 EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
1882 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
1883 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
1884 for (i = 1; i <= 0xffff; i++)
1886 if (!strchrW(ligatures_src, i))
1891 ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1892 EXPECT_LEN(2); EXPECT_VALID;
1893 ok(dst[0] == src[0],
1894 "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n",
1900 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1905 #define LCID_OK(l) \
1906 ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
1907 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
1908 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
1909 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
1910 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
1912 static void test_ConvertDefaultLocale(void)
1916 /* Doesn't change lcid, even if non default sublang/sort used */
1917 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
1918 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
1919 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
1920 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
1922 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
1923 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
1924 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
1925 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
1926 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
1927 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
1928 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
1930 /* Invariant language is not treated specially */
1931 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
1932 LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
1933 MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
1935 /* User/system default languages alone are not mapped */
1936 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
1937 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
1940 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
1941 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
1942 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
1945 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
1946 DWORD dwFlags, LONG_PTR lParam)
1948 trace("%08lx, %s, %s, %08lx, %08lx\n",
1949 lgrpid, lpszNum, lpszName, dwFlags, lParam);
1951 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
1952 "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
1954 /* If lParam is one, we are calling with flags defaulted from 0 */
1955 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
1956 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
1961 static void test_EnumSystemLanguageGroupsA(void)
1963 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
1966 /* No enumeration proc */
1968 pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
1973 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
1976 /* No flags - defaults to LGRPID_INSTALLED */
1978 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
1981 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
1982 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
1986 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
1989 trace("%08lx, %08lx, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
1991 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
1992 "Enumerated grp %ld not valid\n", lgrpid);
1993 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
1994 "Enumerated grp locale %ld not valid\n", lcid);
1998 static void test_EnumLanguageGroupLocalesA(void)
2000 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2003 /* No enumeration proc */
2005 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2008 /* lgrpid too small */
2010 pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2013 /* lgrpid too big */
2015 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2018 /* dwFlags is reserved */
2020 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2023 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2026 static void test_SetLocaleInfoA(void)
2029 LCID lcid = GetUserDefaultLCID();
2033 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2038 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2043 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2047 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam) {
2048 trace("%s %08lx\n", value, lParam);
2052 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam) {
2053 ok(!enumCount, "callback called again unexpected\n");
2058 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam) {
2059 ok(0,"callback called unexpected\n");
2063 static void test_EnumUILanguageA(void)
2065 if (!pEnumUILanguagesA) {
2066 trace("EnumUILanguagesA is not available on Win9x\n");
2070 SetLastError(ERROR_SUCCESS);
2071 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2072 EXPECT_TRUE; EXPECT_VALID;
2075 SetLastError(ERROR_SUCCESS);
2076 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2077 EXPECT_TRUE; EXPECT_VALID;
2079 SetLastError(ERROR_SUCCESS);
2080 ret = pEnumUILanguagesA(NULL, 0, 0);
2081 EXPECT_FALSE; EXPECT_INVALID;
2083 SetLastError(ERROR_SUCCESS);
2084 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2085 EXPECT_FALSE; EXPECT_FLAGS;
2087 SetLastError(ERROR_SUCCESS);
2088 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2089 EXPECT_FALSE; EXPECT_INVALID;
2094 InitFunctionPointers();
2097 test_EnumTimeFormats();
2099 test_GetLocaleInfoA();
2100 test_GetTimeFormatA();
2101 test_GetDateFormatA();
2102 test_GetDateFormatW();
2103 test_GetCurrencyFormatA(); /* Also tests the W version */
2104 test_GetNumberFormatA(); /* Also tests the W version */
2105 test_CompareStringA();
2106 test_LCMapStringA();
2107 test_LCMapStringW();
2110 test_ConvertDefaultLocale();
2111 test_EnumSystemLanguageGroupsA();
2112 test_EnumLanguageGroupLocalesA();
2113 test_SetLocaleInfoA();
2114 #if 0 /* this requires collation table patch to make it MS compatible */
2117 test_EnumUILanguageA();