Rewrote the collapsing of . and .. in RtlGetFullPathName_U for better
[wine.git] / dlls / kernel / tests / locale.c
blob5ef5b4006105114564c46e317705acb15341d295
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 for ( ; *str; str++) if (*str == ch) return (WCHAR *)str;
55 return NULL;
58 inline static 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;
68 typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
69 DWORD, LONG_PTR);
70 static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
71 typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
72 LGRPID, DWORD, LONG_PTR);
73 static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
75 typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
76 static FoldStringAFn pFoldStringA;
77 typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
78 static FoldStringWFn pFoldStringW;
80 typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
81 static IsValidLanguageGroupFn pIsValidLanguageGroup;
83 static void InitFunctionPointers(void)
85 hKernel32 = GetModuleHandleA("kernel32");
87 if (hKernel32)
89 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
90 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
91 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
92 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
93 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
97 #define eq(received, expected, label, type) \
98 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
99 (label), (received), (expected))
101 #define BUFFER_SIZE 128
102 char GlobalBuffer[BUFFER_SIZE]; /* Buffer used by callback function */
103 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
105 #define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (len), ret)
106 #define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
107 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError())
108 #define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
109 "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError())
110 #define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
111 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
112 #define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
113 GetLastError() == ERROR_INVALID_PARAMETER, \
114 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
115 #define EXPECT_VALID ok(GetLastError() == 0, \
116 "Expected GetLastError() == 0, got %ld\n", GetLastError())
118 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
119 #define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
120 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
121 "Expected '%s', got '%s'\n", Expected, buffer)
123 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
124 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
125 SetLastError(0); buffer[0] = '\0'
126 #define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
127 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
129 #define NUO LOCALE_NOUSEROVERRIDE
131 static void test_GetLocaleInfoA()
133 int ret;
134 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
135 char buffer[BUFFER_SIZE];
137 ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
139 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
140 * partially fill the buffer even if it is too short. See bug 637.
142 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
143 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
144 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
146 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
147 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
148 EXPECT_BUFFER; EXPECT_LEN(0);
149 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
151 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
152 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
153 EXPECT_VALID; EXPECT_LEN(7);
154 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
157 static void test_GetTimeFormatA()
159 int ret;
160 SYSTEMTIME curtime;
161 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
162 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
164 memset(&curtime, 2, sizeof(SYSTEMTIME));
165 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
166 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
167 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
169 curtime.wHour = 8;
170 curtime.wMinute = 56;
171 curtime.wSecond = 13;
172 curtime.wMilliseconds = 22;
173 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
174 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
175 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
177 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficent buffer */
178 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
179 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
181 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
182 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
183 EXPECT_VALID; EXPECT_LENA;
185 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
186 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
187 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
189 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
190 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
191 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
193 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
194 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
195 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
197 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
198 strcpy(Expected, "8:56 AM");
199 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
200 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
202 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
203 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
204 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
206 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
207 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
208 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
210 STRINGSA("t/tt", "A/AM"); /* AM time marker */
211 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
212 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
214 curtime.wHour = 13;
215 STRINGSA("t/tt", "P/PM"); /* PM time marker */
216 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
217 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
219 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
220 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
221 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
223 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
224 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
225 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
227 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
228 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
229 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
231 curtime.wHour = 14; /* change this to 14 or 2pm */
232 curtime.wMinute = 5;
233 curtime.wSecond = 3;
234 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 */
235 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
236 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
238 curtime.wHour = 0;
239 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
240 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
241 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
243 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
244 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
245 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
247 /* try to convert formatting strings with more than two letters
248 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
249 * NOTE: We expect any letter for which there is an upper case value
250 * we should see a replacement. For letters that DO NOT have
251 * upper case values we should see NO REPLACEMENT.
253 curtime.wHour = 8;
254 curtime.wMinute = 56;
255 curtime.wSecond = 13;
256 curtime.wMilliseconds = 22;
257 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
258 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
259 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
260 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
262 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
263 strcpy(buffer, "text");
264 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
265 EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
267 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
268 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
269 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
270 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
272 STRINGSA("'''", "'"); /* invalid quoted string */
273 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
274 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
276 /* test that msdn suggested single quotation usage works as expected */
277 STRINGSA("''''", "'"); /* single quote mark */
278 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
279 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
281 STRINGSA("''HHHHHH", "08"); /* Normal use */
282 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
283 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
285 /* and test for normal use of the single quotation mark */
286 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
287 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
288 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
290 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
291 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
292 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
294 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
295 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
296 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
298 curtime.wHour = 25;
299 STRINGSA("'123'tt", ""); /* Invalid time */
300 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
301 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
303 curtime.wHour = 12;
304 curtime.wMonth = 60; /* Invalid */
305 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
306 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
307 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
310 static void test_GetDateFormatA()
312 int ret;
313 SYSTEMTIME curtime;
314 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
315 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
317 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
318 STRINGSA("ddd',' MMM dd yy","");
319 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
320 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
322 curtime.wYear = 2002;
323 curtime.wMonth = 5;
324 curtime.wDay = 4;
325 curtime.wDayOfWeek = 3;
326 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
327 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
328 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
330 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
331 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
332 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
334 curtime.wHour = 36; /* Invalid */
335 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
336 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
337 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
339 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
340 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
341 EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA;
343 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
344 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
345 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
347 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
348 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
349 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
351 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
352 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
353 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
355 /* test for expected DATE_YEARMONTH behavior with null format */
356 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
357 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
358 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
359 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
361 /* Test that using invalid DATE_* flags results in the correct error */
362 /* and return values */
363 STRINGSA("m/d/y", ""); /* Invalid flags */
364 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
365 &curtime, input, buffer, COUNTOF(buffer));
366 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
369 static void test_GetDateFormatW()
371 int ret;
372 SYSTEMTIME curtime;
373 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
374 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
376 STRINGSW("",""); /* If flags is not zero then format must be NULL */
377 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
378 input, buffer, COUNTOF(buffer));
379 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
380 return;
381 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW;
383 STRINGSW("",""); /* NULL buffer, len > 0 */
384 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
385 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
387 STRINGSW("",""); /* NULL buffer, len == 0 */
388 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
389 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
391 curtime.wYear = 2002;
392 curtime.wMonth = 10;
393 curtime.wDay = 23;
394 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
395 curtime.wHour = 65432; /* Invalid */
396 curtime.wMinute = 34512; /* Invalid */
397 curtime.wSecond = 65535; /* Invalid */
398 curtime.wMilliseconds = 12345;
399 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
400 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
401 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
405 #define CY_POS_LEFT 0
406 #define CY_POS_RIGHT 1
407 #define CY_POS_LEFT_SPACE 2
408 #define CY_POS_RIGHT_SPACE 3
410 static void test_GetCurrencyFormatA()
412 static char szDot[] = { '.', '\0' };
413 static char szComma[] = { ',', '\0' };
414 static char szDollar[] = { '$', '\0' };
415 int ret;
416 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
417 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
418 CURRENCYFMTA format;
420 memset(&format, 0, sizeof(format));
422 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
423 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
424 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
426 STRINGSA("23,53",""); /* Invalid character --> Error */
427 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
428 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
430 STRINGSA("--",""); /* Double '-' --> Error */
431 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
432 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
434 STRINGSA("0-",""); /* Trailing '-' --> Error */
435 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
436 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
438 STRINGSA("0..",""); /* Double '.' --> Error */
439 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
440 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
442 STRINGSA(" 0.1",""); /* Leading space --> Error */
443 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
444 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
446 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
447 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
448 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
450 STRINGSA("2353",""); /* Format and flags given --> Error */
451 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
452 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
454 STRINGSA("2353",""); /* Invalid format --> Error */
455 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
456 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
458 STRINGSA("2353","$2,353.00"); /* Valid number */
459 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
460 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
462 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
463 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
464 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
466 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
467 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
468 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
470 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
471 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
472 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
474 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
475 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
476 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
478 format.NumDigits = 0; /* No decimal separator */
479 format.LeadingZero = 0;
480 format.Grouping = 0; /* No grouping char */
481 format.NegativeOrder = 0;
482 format.PositiveOrder = CY_POS_LEFT;
483 format.lpDecimalSep = szDot;
484 format.lpThousandSep = szComma;
485 format.lpCurrencySymbol = szDollar;
487 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
488 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
489 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
491 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
492 STRINGSA("2353","$2353.0");
493 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
494 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
496 format.Grouping = 2; /* Group by 100's */
497 STRINGSA("2353","$23,53.0");
498 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
499 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
501 format.LeadingZero = 1; /* Always provide leading zero */
502 STRINGSA(".5","$0.5");
503 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
504 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
506 format.PositiveOrder = CY_POS_RIGHT;
507 STRINGSA("1","1.0$");
508 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
509 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
511 format.PositiveOrder = CY_POS_LEFT_SPACE;
512 STRINGSA("1","$ 1.0");
513 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
514 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
516 format.PositiveOrder = CY_POS_RIGHT_SPACE;
517 STRINGSA("1","1.0 $");
518 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
519 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
521 format.NegativeOrder = 0;
522 STRINGSA("-1","($1.0)");
523 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
524 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
526 format.NegativeOrder = 1;
527 STRINGSA("-1","-$1.0");
528 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
529 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
531 format.NegativeOrder = 2;
532 STRINGSA("-1","$-1.0");
533 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
534 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
536 format.NegativeOrder = 3;
537 STRINGSA("-1","$1.0-");
538 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
539 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
541 format.NegativeOrder = 4;
542 STRINGSA("-1","(1.0$)");
543 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
544 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
546 format.NegativeOrder = 5;
547 STRINGSA("-1","-1.0$");
548 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
549 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
551 format.NegativeOrder = 6;
552 STRINGSA("-1","1.0-$");
553 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
554 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
556 format.NegativeOrder = 7;
557 STRINGSA("-1","1.0$-");
558 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
559 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
561 format.NegativeOrder = 8;
562 STRINGSA("-1","-1.0 $");
563 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
564 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
566 format.NegativeOrder = 9;
567 STRINGSA("-1","-$ 1.0");
568 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
569 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
571 format.NegativeOrder = 10;
572 STRINGSA("-1","1.0 $-");
573 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
574 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
576 format.NegativeOrder = 11;
577 STRINGSA("-1","$ 1.0-");
578 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
579 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
581 format.NegativeOrder = 12;
582 STRINGSA("-1","$ -1.0");
583 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
584 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
586 format.NegativeOrder = 13;
587 STRINGSA("-1","1.0- $");
588 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
589 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
591 format.NegativeOrder = 14;
592 STRINGSA("-1","($ 1.0)");
593 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
594 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
596 format.NegativeOrder = 15;
597 STRINGSA("-1","(1.0 $)");
598 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
599 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
602 #define NEG_PARENS 0 /* "(1.1)" */
603 #define NEG_LEFT 1 /* "-1.1" */
604 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
605 #define NEG_RIGHT 3 /* "1.1-" */
606 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
608 static void test_GetNumberFormatA()
610 static char szDot[] = { '.', '\0' };
611 static char szComma[] = { ',', '\0' };
612 int ret;
613 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
614 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
615 NUMBERFMTA format;
617 memset(&format, 0, sizeof(format));
619 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
620 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
621 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
623 STRINGSA("23,53",""); /* Invalid character --> Error */
624 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
625 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
627 STRINGSA("--",""); /* Double '-' --> Error */
628 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
629 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
631 STRINGSA("0-",""); /* Trailing '-' --> Error */
632 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
633 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
635 STRINGSA("0..",""); /* Double '.' --> Error */
636 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
637 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
639 STRINGSA(" 0.1",""); /* Leading space --> Error */
640 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
641 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
643 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
644 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
645 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
647 STRINGSA("2353",""); /* Format and flags given --> Error */
648 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
649 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
651 STRINGSA("2353",""); /* Invalid format --> Error */
652 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
653 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
655 STRINGSA("2353","2,353.00"); /* Valid number */
656 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
657 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
659 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
660 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
661 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
663 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
664 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
665 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
667 STRINGSA("2353.1","2,353.10"); /* Valid real number */
668 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
669 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
671 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
672 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
673 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
675 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
676 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
677 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
679 format.NumDigits = 0; /* No decimal separator */
680 format.LeadingZero = 0;
681 format.Grouping = 0; /* No grouping char */
682 format.NegativeOrder = 0;
683 format.lpDecimalSep = szDot;
684 format.lpThousandSep = szComma;
686 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
687 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
688 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
690 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
691 STRINGSA("2353","2353.0");
692 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
693 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
695 format.Grouping = 2; /* Group by 100's */
696 STRINGSA("2353","23,53.0");
697 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
698 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
700 format.LeadingZero = 1; /* Always provide leading zero */
701 STRINGSA(".5","0.5");
702 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
703 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
705 format.NegativeOrder = NEG_PARENS;
706 STRINGSA("-1","(1.0)");
707 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
708 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
710 format.NegativeOrder = NEG_LEFT;
711 STRINGSA("-1","-1.0");
712 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
713 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
715 format.NegativeOrder = NEG_LEFT_SPACE;
716 STRINGSA("-1","- 1.0");
717 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
718 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
720 format.NegativeOrder = NEG_RIGHT;
721 STRINGSA("-1","1.0-");
722 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
723 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
725 format.NegativeOrder = NEG_RIGHT_SPACE;
726 STRINGSA("-1","1.0 -");
727 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
728 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
730 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
732 if (IsValidLocale(lcid, 0))
734 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
735 Expected[3] = 160; /* Non breaking space */
736 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
737 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
742 /* Callback function used by TestEnumTimeFormats */
743 static BOOL CALLBACK EnumTimeFormatsProc(char * lpTimeFormatString)
745 trace("%s\n", lpTimeFormatString);
746 strcpy(GlobalBuffer, lpTimeFormatString);
747 #if 0
748 return TRUE;
749 #endif
750 return FALSE;
753 void test_EnumTimeFormats()
755 int ret;
756 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
758 GlobalBuffer[0] = '\0';
759 ret = EnumTimeFormatsA(EnumTimeFormatsProc, lcid, 0);
760 ok (ret == 1 && !strcmp(GlobalBuffer,"h:mm:ss tt"), "Expected %d '%s'\n", ret, GlobalBuffer);
763 static void test_CompareStringA()
765 int ret;
766 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
768 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
769 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
771 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
772 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
774 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
775 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
777 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
778 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
780 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
782 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
783 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
785 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
786 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
788 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
789 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
791 SetLastError(0xdeadbeef);
792 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1);
793 ok(GetLastError() == ERROR_INVALID_FLAGS,
794 "unexpected error code %ld\n", GetLastError());
795 ok(!ret, "CompareStringA must fail with invalid flag\n");
797 ret = lstrcmpA("", "");
798 ok (!ret, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
800 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
801 ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
803 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
804 ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
806 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
807 ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
809 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
810 ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
812 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
813 ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
815 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
816 ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
818 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
819 ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
821 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
822 ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
824 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
825 ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
827 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
828 ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
830 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
831 ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
833 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
834 ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
836 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
837 ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
839 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
840 ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
842 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
843 ok( ret == 3, "a vs { expected 3, got %d\n", ret);
845 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
846 ok( ret == 3, "A vs { expected 3, got %d\n", ret);
848 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
849 ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
851 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
852 ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
854 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
855 ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
857 /* hyphen and apostrophe are treated differently depending on
858 * whether SORT_STRINGSORT specified or not
860 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
861 ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
863 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
864 ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
866 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
867 ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
869 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
870 ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
872 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
873 ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
875 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
876 ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
878 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
879 ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
881 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
882 ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
884 #if 0 /* this requires collation table patch to make it MS compatible */
885 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
886 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
888 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
889 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
891 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
892 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
894 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
895 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
897 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
898 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
900 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
901 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
903 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
904 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
906 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
907 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
909 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
910 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
912 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
913 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
915 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
916 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
918 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
919 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
920 #endif
922 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
923 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
925 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
926 ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
928 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
929 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 2, got %d\n", ret);
931 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
932 ok(ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 2, got %d\n", ret);
935 void test_LCMapStringA(void)
937 int ret, ret2;
938 char buf[256], buf2[256];
939 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
940 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
941 static const char symbols_stripped[] = "justateststring1";
943 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
944 upper_case, -1, buf, sizeof(buf));
945 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
946 ok(GetLastError() == ERROR_INVALID_FLAGS,
947 "unexpected error code %ld\n", GetLastError());
949 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
950 upper_case, -1, buf, sizeof(buf));
951 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
952 ok(GetLastError() == ERROR_INVALID_FLAGS,
953 "unexpected error code %ld\n", GetLastError());
955 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
957 upper_case, -1, buf, sizeof(buf));
958 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
959 ok(GetLastError() == ERROR_INVALID_FLAGS,
960 "unexpected error code %ld\n", GetLastError());
962 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
963 upper_case, -1, buf, sizeof(buf));
964 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
965 ok(GetLastError() == ERROR_INVALID_FLAGS,
966 "unexpected error code %ld\n", GetLastError());
968 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
969 SetLastError(0xdeadbeef);
970 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
971 upper_case, -1, buf, sizeof(buf));
972 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
973 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
975 /* test LCMAP_LOWERCASE */
976 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
977 upper_case, -1, buf, sizeof(buf));
978 ok(ret == lstrlenA(upper_case) + 1,
979 "ret %d, error %ld, expected value %d\n",
980 ret, GetLastError(), lstrlenA(upper_case) + 1);
981 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
983 /* test LCMAP_UPPERCASE */
984 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
985 lower_case, -1, buf, sizeof(buf));
986 ok(ret == lstrlenA(lower_case) + 1,
987 "ret %d, error %ld, expected value %d\n",
988 ret, GetLastError(), lstrlenA(lower_case) + 1);
989 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
991 /* test buffer overflow */
992 SetLastError(0xdeadbeef);
993 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
994 lower_case, -1, buf, 4);
995 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
996 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
998 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
999 lstrcpyA(buf, lower_case);
1000 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1001 buf, -1, buf, sizeof(buf));
1002 if (!ret) /* Win9x */
1003 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1004 else
1006 ok(ret == lstrlenA(lower_case) + 1,
1007 "ret %d, error %ld, expected value %d\n",
1008 ret, GetLastError(), lstrlenA(lower_case) + 1);
1009 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1011 lstrcpyA(buf, upper_case);
1012 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1013 buf, -1, buf, sizeof(buf));
1014 if (!ret) /* Win9x */
1015 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1016 else
1018 ok(ret == lstrlenA(upper_case) + 1,
1019 "ret %d, error %ld, expected value %d\n",
1020 ret, GetLastError(), lstrlenA(lower_case) + 1);
1021 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1024 /* otherwise src == dst should fail */
1025 SetLastError(0xdeadbeef);
1026 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1027 buf, 10, buf, sizeof(buf));
1028 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1029 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1030 "unexpected error code %ld\n", GetLastError());
1031 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1033 /* test whether '\0' is always appended */
1034 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1035 upper_case, -1, buf, sizeof(buf));
1036 ok(ret, "LCMapStringA must succeed\n");
1037 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1038 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1039 ok(ret, "LCMapStringA must succeed\n");
1040 ok(ret == ret2, "lengths of sort keys must be equal\n");
1041 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1043 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1044 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1045 upper_case, -1, buf, sizeof(buf));
1046 ok(ret, "LCMapStringA must succeed\n");
1047 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1048 lower_case, -1, buf2, sizeof(buf2));
1049 ok(ret2, "LCMapStringA must succeed\n");
1050 ok(ret == ret2, "lengths of sort keys must be equal\n");
1051 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1053 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1054 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1055 lower_case, -1, buf, sizeof(buf));
1056 ok(ret, "LCMapStringA must succeed\n");
1057 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1058 lower_case, -1, buf2, sizeof(buf2));
1059 ok(ret2, "LCMapStringA must succeed\n");
1060 ok(ret == ret2, "lengths of sort keys must be equal\n");
1061 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1063 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1064 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1065 lower_case, -1, buf, sizeof(buf));
1066 ok(ret, "LCMapStringA must succeed\n");
1067 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1068 symbols_stripped, -1, buf2, sizeof(buf2));
1069 ok(ret2, "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 NORM_IGNORENONSPACE */
1074 lstrcpyA(buf, "foo");
1075 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1076 lower_case, -1, buf, sizeof(buf));
1077 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1078 lstrlenA(lower_case) + 1, ret);
1079 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1081 /* test NORM_IGNORESYMBOLS */
1082 lstrcpyA(buf, "foo");
1083 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1084 lower_case, -1, buf, sizeof(buf));
1085 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1086 lstrlenA(symbols_stripped) + 1, ret);
1087 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1089 /* test srclen = 0 */
1090 SetLastError(0xdeadbeef);
1091 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1092 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1093 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1094 "unexpected error code %ld\n", GetLastError());
1097 void test_LCMapStringW(void)
1099 int ret, ret2;
1100 WCHAR buf[256], buf2[256];
1101 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1102 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};
1103 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};
1104 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1105 static const WCHAR fooW[] = {'f','o','o',0};
1107 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1108 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1109 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1111 trace("Skipping LCMapStringW tests on Win9x\n");
1112 return;
1114 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1115 ok(GetLastError() == ERROR_INVALID_FLAGS,
1116 "unexpected error code %ld\n", GetLastError());
1118 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1119 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1120 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1121 ok(GetLastError() == ERROR_INVALID_FLAGS,
1122 "unexpected error code %ld\n", GetLastError());
1124 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1125 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1126 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1127 ok(GetLastError() == ERROR_INVALID_FLAGS,
1128 "unexpected error code %ld\n", GetLastError());
1130 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1131 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1132 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1133 ok(GetLastError() == ERROR_INVALID_FLAGS,
1134 "unexpected error code %ld\n", GetLastError());
1136 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1137 SetLastError(0xdeadbeef);
1138 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1139 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1140 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
1141 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1143 /* test LCMAP_LOWERCASE */
1144 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1145 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1146 ok(ret == lstrlenW(upper_case) + 1,
1147 "ret %d, error %ld, expected value %d\n",
1148 ret, GetLastError(), lstrlenW(upper_case) + 1);
1149 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1151 /* test LCMAP_UPPERCASE */
1152 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1153 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1154 ok(ret == lstrlenW(lower_case) + 1,
1155 "ret %d, error %ld, expected value %d\n",
1156 ret, GetLastError(), lstrlenW(lower_case) + 1);
1157 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1159 /* test buffer overflow */
1160 SetLastError(0xdeadbeef);
1161 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1162 lower_case, -1, buf, 4);
1163 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1164 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1166 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1167 lstrcpyW(buf, lower_case);
1168 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1169 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1170 ok(ret == lstrlenW(lower_case) + 1,
1171 "ret %d, error %ld, expected value %d\n",
1172 ret, GetLastError(), lstrlenW(lower_case) + 1);
1173 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1175 lstrcpyW(buf, upper_case);
1176 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1177 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1178 ok(ret == lstrlenW(upper_case) + 1,
1179 "ret %d, error %ld, expected value %d\n",
1180 ret, GetLastError(), lstrlenW(lower_case) + 1);
1181 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1183 /* otherwise src == dst should fail */
1184 SetLastError(0xdeadbeef);
1185 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1186 buf, 10, buf, sizeof(buf));
1187 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1188 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1189 "unexpected error code %ld\n", GetLastError());
1190 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1192 /* test whether '\0' is always appended */
1193 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1194 upper_case, -1, buf, sizeof(buf));
1195 ok(ret, "LCMapStringW must succeed\n");
1196 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1197 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1198 ok(ret, "LCMapStringW must succeed\n");
1199 ok(ret == ret2, "lengths of sort keys must be equal\n");
1200 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1202 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1203 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1204 upper_case, -1, buf, sizeof(buf));
1205 ok(ret, "LCMapStringW must succeed\n");
1206 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1207 lower_case, -1, buf2, sizeof(buf2));
1208 ok(ret2, "LCMapStringW must succeed\n");
1209 ok(ret == ret2, "lengths of sort keys must be equal\n");
1210 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1212 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1213 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1214 lower_case, -1, buf, sizeof(buf));
1215 ok(ret, "LCMapStringW must succeed\n");
1216 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1217 lower_case, -1, buf2, sizeof(buf2));
1218 ok(ret2, "LCMapStringW must succeed\n");
1219 ok(ret == ret2, "lengths of sort keys must be equal\n");
1220 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1222 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1223 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1224 lower_case, -1, buf, sizeof(buf));
1225 ok(ret, "LCMapStringW must succeed\n");
1226 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1227 symbols_stripped, -1, buf2, sizeof(buf2));
1228 ok(ret2, "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 NORM_IGNORENONSPACE */
1233 lstrcpyW(buf, fooW);
1234 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1235 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1236 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1237 lstrlenW(lower_case) + 1, ret);
1238 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1240 /* test NORM_IGNORESYMBOLS */
1241 lstrcpyW(buf, fooW);
1242 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1243 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1244 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1245 lstrlenW(symbols_stripped) + 1, ret);
1246 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1248 /* test srclen = 0 */
1249 SetLastError(0xdeadbeef);
1250 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1251 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1252 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1253 "unexpected error code %ld\n", GetLastError());
1256 #if 0 /* this requires collation table patch to make it MS compatible */
1257 const char *strings_sorted[] =
1259 "'",
1260 "-",
1261 "!",
1262 "\"",
1263 ".",
1264 ":",
1265 "\\",
1266 "_",
1267 "`",
1268 "{",
1269 "}",
1270 "+",
1271 "0",
1272 "1",
1273 "2",
1274 "3",
1275 "4",
1276 "5",
1277 "6",
1278 "7",
1279 "8",
1280 "9",
1281 "a",
1282 "A",
1283 "b",
1284 "B",
1285 "c",
1289 const char *strings[] =
1291 "C",
1292 "\"",
1293 "9",
1294 "'",
1295 "}",
1296 "-",
1297 "7",
1298 "+",
1299 "`",
1300 "1",
1301 "a",
1302 "5",
1303 "\\",
1304 "8",
1305 "B",
1306 "3",
1307 "_",
1308 "6",
1309 "{",
1310 "2",
1311 "c",
1312 "4",
1313 "!",
1314 "0",
1315 "A",
1316 ":",
1317 "b",
1321 static int compare_string1(const void *e1, const void *e2)
1323 const char *s1 = *(const char **)e1;
1324 const char *s2 = *(const char **)e2;
1326 return lstrcmpA(s1, s2);
1329 static int compare_string2(const void *e1, const void *e2)
1331 const char *s1 = *(const char **)e1;
1332 const char *s2 = *(const char **)e2;
1334 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1337 static int compare_string3(const void *e1, const void *e2)
1339 const char *s1 = *(const char **)e1;
1340 const char *s2 = *(const char **)e2;
1341 char key1[256], key2[256];
1343 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1344 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1345 return strcmp(key1, key2);
1348 static void test_sorting(void)
1350 char buf[256];
1351 char **str_buf = (char **)buf;
1352 int i;
1354 assert(sizeof(buf) >= sizeof(strings));
1356 /* 1. sort using lstrcmpA */
1357 memcpy(buf, strings, sizeof(strings));
1358 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1359 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1361 ok(!strcmp(strings_sorted[i], str_buf[i]),
1362 "qsort using lstrcmpA failed for element %d\n", i);
1364 /* 2. sort using CompareStringA */
1365 memcpy(buf, strings, sizeof(strings));
1366 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1367 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1369 ok(!strcmp(strings_sorted[i], str_buf[i]),
1370 "qsort using CompareStringA failed for element %d\n", i);
1372 /* 3. sort using sort keys */
1373 memcpy(buf, strings, sizeof(strings));
1374 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1375 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1377 ok(!strcmp(strings_sorted[i], str_buf[i]),
1378 "qsort using sort keys failed for element %d\n", i);
1381 #endif
1383 static void test_FoldStringA(void)
1385 int ret, i;
1386 char src[256], dst[256];
1387 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1388 static const char digits_dst[] = { '1','2','3','\0' };
1389 static const char composite_src[] =
1391 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1392 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1393 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1394 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1395 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1396 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1397 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1398 0xfb,0xfc,0xfd,0xff,'\0'
1400 static const char composite_dst[] =
1402 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1403 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1404 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1405 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1406 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1407 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1408 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1409 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1410 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1411 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1412 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1413 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1414 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1415 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1416 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1418 static const char ligatures_src[] =
1420 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1422 static const char ligatures_dst[] =
1424 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1427 if (!pFoldStringA)
1428 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1430 /* these tests are locale specific */
1431 if (GetACP() != 1252)
1433 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1434 return;
1437 /* MAP_FOLDDIGITS */
1438 SetLastError(0);
1439 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1440 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1441 return;
1442 EXPECT_LEN(4); EXPECT_VALID;
1443 ok(strcmp(dst, digits_dst) == 0,
1444 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1445 for (i = 1; i < 256; i++)
1447 if (!strchr(digits_src, i))
1449 src[0] = i;
1450 src[1] = '\0';
1451 SetLastError(0);
1452 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1453 EXPECT_LEN(2); EXPECT_VALID;
1454 ok(dst[0] == src[0],
1455 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1459 /* MAP_EXPAND_LIGATURES */
1460 SetLastError(0);
1461 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1462 EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
1463 ok(strcmp(dst, ligatures_dst) == 0,
1464 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1465 for (i = 1; i < 256; i++)
1467 if (!strchr(ligatures_src, i))
1469 src[0] = i;
1470 src[1] = '\0';
1471 SetLastError(0);
1472 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1473 EXPECT_LEN(2); EXPECT_VALID;
1474 ok(dst[0] == src[0],
1475 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1479 /* MAP_COMPOSITE */
1480 SetLastError(0);
1481 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1482 EXPECT_VALID;
1483 todo_wine
1485 /* Wine gets close, but doesn't produce quite the same result as native */
1486 EXPECT_LEN(121);
1487 ok(strcmp(dst, composite_dst) == 0,
1488 "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
1491 for (i = 1; i < 256; i++)
1493 if (!strchr(composite_src, i))
1495 src[0] = i;
1496 src[1] = '\0';
1497 SetLastError(0);
1498 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1499 EXPECT_LEN(2); EXPECT_VALID;
1500 ok(dst[0] == src[0],
1501 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1502 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1506 /* MAP_FOLDCZONE */
1507 for (i = 1; i < 256; i++)
1509 src[0] = i;
1510 src[1] = '\0';
1511 SetLastError(0);
1512 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1513 EXPECT_LEN(2); EXPECT_VALID;
1514 ok(src[0] == dst[0],
1515 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1516 (unsigned char)src[0], (unsigned char)dst[0]);
1519 /* MAP_PRECOMPOSED */
1520 for (i = 1; i < 256; i++)
1522 src[0] = i;
1523 src[1] = '\0';
1524 SetLastError(0);
1525 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1526 EXPECT_LEN(2); EXPECT_VALID;
1527 ok(src[0] == dst[0],
1528 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1529 (unsigned char)src[0], (unsigned char)dst[0]);
1533 static void test_FoldStringW(void)
1535 int ret;
1536 size_t i, j;
1537 WCHAR src[256], dst[256], ch, prev_ch = 1;
1538 static const DWORD badFlags[] =
1541 MAP_PRECOMPOSED|MAP_COMPOSITE,
1542 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1543 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1545 /* Ranges of digits 0-9 : Must be sorted! */
1546 static const WCHAR digitRanges[] =
1548 0x0030, /* '0'-'9' */
1549 0x0660, /* Eastern Arabic */
1550 0x06F0, /* Arabic - Hindu */
1551 0x0966, /* Devengari */
1552 0x09E6, /* Bengalii */
1553 0x0A66, /* Gurmukhi */
1554 0x0AE6, /* Gujarati */
1555 0x0B66, /* Oriya */
1556 0x0BE6, /* Tamil - No 0 */
1557 0x0C66, /* Telugu */
1558 0x0CE6, /* Kannada */
1559 0x0D66, /* Maylayalam */
1560 0x0E50, /* Thai */
1561 0x0ED0, /* Laos */
1562 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1563 0x2080, /* Subscript */
1564 0x245F, /* Circled - 0 is out of sequence */
1565 0x2473, /* Bracketed */
1566 0x2487, /* Full stop */
1567 0x2775, /* Inverted circled - No 0 */
1568 0x277F, /* Patterned circled - No 0 */
1569 0x2789, /* Inverted Patterned circled - No 0 */
1570 0xff10, /* Pliene chasse (?) */
1571 0xffff /* Terminator */
1573 /* Digits which are represented, but out of sequence */
1574 static const WCHAR outOfSequenceDigits[] =
1576 0xB9, /* Superscript 1 */
1577 0xB2, /* Superscript 2 */
1578 0xB3, /* Superscript 3 */
1579 0x24EA, /* Circled 0 */
1580 '\0' /* Terminator */
1582 /* Digits in digitRanges for which no representation is available */
1583 static const WCHAR noDigitAvailable[] =
1585 0x0BE6, /* No Tamil 0 */
1586 0x2473, /* No Bracketed 0 */
1587 0x2487, /* No 0 Full stop */
1588 0x2775, /* No inverted circled 0 */
1589 0x277F, /* No patterned circled */
1590 0x2789, /* No inverted Patterned circled */
1591 '\0' /* Terminator */
1593 /* Compatibility conversion results */
1594 static const WCHAR compat_F900_FA2F[256+48] =
1596 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
1597 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
1598 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
1599 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
1600 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
1601 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
1602 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
1603 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
1604 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
1605 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
1606 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
1607 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
1608 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
1609 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
1610 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
1611 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
1612 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
1613 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
1614 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
1615 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
1616 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
1617 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
1618 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
1619 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
1620 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
1621 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
1622 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
1623 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
1624 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
1625 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
1626 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
1627 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
1628 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
1629 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
1630 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
1631 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
1632 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
1633 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
1635 static const WCHAR compat_FE30_FEF7[200] =
1637 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
1638 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
1639 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
1640 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
1641 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
1642 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
1643 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
1644 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
1645 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
1646 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
1647 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
1648 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
1649 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
1650 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
1651 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
1652 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
1653 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
1654 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
1655 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
1656 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
1657 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
1658 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
1659 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
1660 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
1661 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
1663 static const WCHAR compat_FF00_FFEF[240] =
1665 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1666 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1667 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1668 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
1669 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1670 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1671 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1672 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
1673 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1674 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1675 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1676 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1677 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
1678 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
1679 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
1680 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
1681 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
1682 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
1683 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
1684 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
1685 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
1686 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
1687 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
1688 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
1689 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
1690 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
1691 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
1692 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
1693 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
1694 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
1696 static const WCHAR ligatures_src[] =
1698 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1699 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1700 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1701 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
1702 0xfb04, 0xfb05, 0xfb06, '\0'
1704 static const WCHAR ligatures_dst[] =
1706 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
1707 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
1708 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
1709 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
1710 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
1713 if (!pFoldStringW)
1714 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1716 /* Invalid flag combinations */
1717 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1719 src[0] = dst[0] = '\0';
1720 SetLastError(0);
1721 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1722 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1723 return;
1724 EXPECT_LEN(0); EXPECT_FLAGS;
1727 /* src & dst cannot be the same */
1728 SetLastError(0);
1729 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
1730 EXPECT_LEN(0); EXPECT_INVALID;
1732 /* src can't be NULL */
1733 SetLastError(0);
1734 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1735 EXPECT_LEN(0); EXPECT_INVALID;
1737 /* srclen can't be 0 */
1738 SetLastError(0);
1739 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1740 EXPECT_LEN(0); EXPECT_INVALID;
1742 /* dstlen can't be < 0 */
1743 SetLastError(0);
1744 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1745 EXPECT_LEN(0); EXPECT_INVALID;
1747 /* Ret includes terminating NUL which is appended if srclen = -1 */
1748 SetLastError(0);
1749 src[0] = 'A';
1750 src[1] = '\0';
1751 dst[0] = '\0';
1752 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1753 EXPECT_LEN(2); EXPECT_VALID;
1754 ok(dst[0] == 'A' && dst[1] == '\0',
1755 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
1756 'A', '\0', ret, dst[0], dst[1], GetLastError());
1758 /* If size is given, result is not NUL terminated */
1759 SetLastError(0);
1760 src[0] = 'A';
1761 src[1] = 'A';
1762 dst[0] = 'X';
1763 dst[1] = 'X';
1764 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
1765 EXPECT_LEN(1); EXPECT_VALID;
1766 ok(dst[0] == 'A' && dst[1] == 'X',
1767 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
1768 'A','X', ret, dst[0], dst[1], GetLastError());
1770 /* MAP_FOLDDIGITS */
1771 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1773 /* Check everything before this range */
1774 for (ch = prev_ch; ch < digitRanges[j]; ch++)
1776 SetLastError(0);
1777 src[0] = ch;
1778 src[1] = dst[0] = '\0';
1779 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1780 EXPECT_LEN(2); EXPECT_VALID;
1782 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
1783 /* Wine (correctly) maps all Unicode 4.0+ digits */
1784 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF,
1785 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
1788 if (digitRanges[j] == 0xffff)
1789 break; /* Finished the whole code point space */
1791 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1793 WCHAR c;
1795 /* Map out of sequence characters */
1796 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
1797 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
1798 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
1799 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
1800 else c = ch;
1801 SetLastError(0);
1802 src[0] = c;
1803 src[1] = dst[0] = '\0';
1804 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1805 EXPECT_LEN(2); EXPECT_VALID;
1807 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
1808 strchrW(noDigitAvailable, c),
1809 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
1810 ch, '0' + digitRanges[j] - ch, dst[0]);
1812 prev_ch = ch;
1815 /* MAP_FOLDCZONE */
1816 for (ch = 1; ch <0xffff; ch++)
1818 WCHAR expected = 0;
1820 if (ch >= 0xF900 && ch <= 0xFA2F)
1821 expected = compat_F900_FA2F[ch - 0xF900];
1822 else if (ch >= 0xFE30 && ch <= 0xFEF7)
1823 expected = compat_FE30_FEF7[ch - 0xFE30];
1824 else if (ch >= 0xFF00 && ch <= 0xFFEF)
1825 expected = compat_FF00_FFEF[ch - 0xFF00];
1827 if (!expected)
1828 expected = ch;
1830 SetLastError(0);
1831 src[0] = ch;
1832 src[1] = dst[0] = '\0';
1833 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1834 EXPECT_LEN(2); EXPECT_VALID;
1835 ok(dst[0] == expected ||
1836 /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
1837 (ch >= 0xFA0D && ch <= 0xFA47) ||
1838 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || ch == 0xf9f1,
1839 "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
1840 ch, ch, expected, dst[0]);
1843 /* MAP_EXPAND_LIGATURES */
1844 SetLastError(0);
1845 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1846 EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
1847 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
1848 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
1849 for (i = 1; i <= 0xffff; i++)
1851 if (!strchrW(ligatures_src, i))
1853 src[0] = i;
1854 src[1] = '\0';
1855 SetLastError(0);
1856 ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1857 EXPECT_LEN(2); EXPECT_VALID;
1858 ok(dst[0] == src[0],
1859 "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n",
1860 i, src[0], dst[0]);
1864 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1869 #define LCID_OK(l) \
1870 ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
1871 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
1872 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
1873 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
1874 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
1876 static void test_ConvertDefaultLocale(void)
1878 LCID lcid;
1880 /* Doesn't change lcid, even if non default sublang/sort used */
1881 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
1882 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
1883 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
1884 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
1886 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
1887 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
1888 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
1889 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
1890 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
1891 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
1892 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
1894 /* Invariant language is not treated specially */
1895 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
1896 LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
1897 MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
1899 /* User/system default languages alone are not mapped */
1900 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
1901 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
1903 /* Default lcids */
1904 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
1905 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
1906 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
1909 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
1910 DWORD dwFlags, LONG_PTR lParam)
1912 trace("%08lx, %s, %s, %08lx, %08lx\n",
1913 lgrpid, lpszNum, lpszName, dwFlags, lParam);
1915 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
1916 "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
1918 /* If lParam is one, we are calling with flags defaulted from 0 */
1919 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
1920 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
1922 return TRUE;
1925 static void test_EnumSystemLanguageGroupsA(void)
1927 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
1928 return;
1930 /* No enumeration proc */
1931 SetLastError(0);
1932 pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
1933 EXPECT_INVALID;
1935 /* Invalid flags */
1936 SetLastError(0);
1937 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
1938 EXPECT_FLAGS;
1940 /* No flags - defaults to LGRPID_INSTALLED */
1941 SetLastError(0);
1942 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
1943 EXPECT_VALID;
1945 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
1946 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
1950 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
1951 LONG_PTR lParam)
1953 trace("%08lx, %08lx, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
1955 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
1956 "Enumerated grp %ld not valid\n", lgrpid);
1957 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
1958 "Enumerated grp locale %ld not valid\n", lcid);
1959 return TRUE;
1962 static void test_EnumLanguageGroupLocalesA(void)
1964 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
1965 return;
1967 /* No enumeration proc */
1968 SetLastError(0);
1969 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
1970 EXPECT_INVALID;
1972 /* lgrpid too small */
1973 SetLastError(0);
1974 pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
1975 EXPECT_INVALID;
1977 /* lgrpid too big */
1978 SetLastError(0);
1979 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
1980 EXPECT_INVALID;
1982 /* dwFlags is reserved */
1983 SetLastError(0);
1984 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
1985 EXPECT_INVALID;
1987 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
1990 static void test_SetLocaleInfoA(void)
1992 BOOL bRet;
1993 LCID lcid = GetUserDefaultLCID();
1995 /* Null data */
1996 SetLastError(0);
1997 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
1998 EXPECT_INVALID;
2000 /* IDATE */
2001 SetLastError(0);
2002 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2003 EXPECT_FLAGS;
2005 /* ILDATE */
2006 SetLastError(0);
2007 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2008 EXPECT_FLAGS;
2011 START_TEST(locale)
2013 InitFunctionPointers();
2015 #if 0
2016 test_EnumTimeFormats();
2017 #endif
2018 test_GetLocaleInfoA();
2019 test_GetTimeFormatA();
2020 test_GetDateFormatA();
2021 test_GetDateFormatW();
2022 test_GetCurrencyFormatA(); /* Also tests the W version */
2023 test_GetNumberFormatA(); /* Also tests the W version */
2024 test_CompareStringA();
2025 test_LCMapStringA();
2026 test_LCMapStringW();
2027 test_FoldStringA();
2028 test_FoldStringW();
2029 test_ConvertDefaultLocale();
2030 test_EnumSystemLanguageGroupsA();
2031 test_EnumLanguageGroupLocalesA();
2032 test_SetLocaleInfoA();
2033 #if 0 /* this requires collation table patch to make it MS compatible */
2034 test_sorting();
2035 #endif