Weekly spelling fixes.
[wine.git] / dlls / kernel / tests / locale.c
blob94bcf6fc72e82a77bb9072024451aaaddf7a3137
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.
27 #include <stdarg.h>
29 #include "wine/test.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winnls.h"
35 static inline unsigned int strlenW( const WCHAR *str )
37 const WCHAR *s = str;
38 while (*s) s++;
39 return s - str;
42 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
44 if (n <= 0) return 0;
45 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
46 return *str1 - *str2;
49 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
51 for ( ; *str; str++) if (*str == ch) return (WCHAR *)str;
52 return NULL;
55 inline static int isdigitW( WCHAR wc )
57 WORD type;
58 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
59 return type & C1_DIGIT;
62 /* Some functions are only in later versions of kernel32.dll */
63 static HMODULE hKernel32;
65 typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
66 DWORD, LONG_PTR);
67 static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
68 typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
69 LGRPID, DWORD, LONG_PTR);
70 static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
72 typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
73 static FoldStringAFn pFoldStringA;
74 typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
75 static FoldStringWFn pFoldStringW;
77 static void InitFunctionPointers(void)
79 hKernel32 = GetModuleHandleA("kernel32");
81 if (hKernel32)
83 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
84 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
85 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
86 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
90 #define eq(received, expected, label, type) \
91 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
92 (label), (received), (expected))
94 #define BUFFER_SIZE 128
95 char GlobalBuffer[BUFFER_SIZE]; /* Buffer used by callback function */
96 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
98 #define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (len), ret)
99 #define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
100 "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError())
101 #define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
102 "Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError())
103 #define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
104 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
105 #define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
106 GetLastError() == ERROR_INVALID_PARAMETER, \
107 "Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
108 #define EXPECT_VALID ok(GetLastError() == 0, \
109 "Expected GetLastError() == 0, got %ld\n", GetLastError())
111 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
112 #define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
113 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
114 "Expected '%s', got '%s'", Expected, buffer)
116 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
117 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
118 SetLastError(0); buffer[0] = '\0'
119 #define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
120 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
122 #define NUO LOCALE_NOUSEROVERRIDE
124 static void test_GetLocaleInfoA()
126 int ret;
127 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
128 char buffer[BUFFER_SIZE];
130 ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
132 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
133 * partially fill the buffer even if it is too short. See bug 637.
135 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
136 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
137 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
139 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
140 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
141 EXPECT_BUFFER; EXPECT_LEN(0);
142 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
144 SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
145 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
146 EXPECT_VALID; EXPECT_LEN(7);
147 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
150 static void test_GetTimeFormatA()
152 int ret;
153 SYSTEMTIME curtime;
154 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
155 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
157 memset(&curtime, 2, sizeof(SYSTEMTIME));
158 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
159 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
160 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
162 curtime.wHour = 8;
163 curtime.wMinute = 56;
164 curtime.wSecond = 13;
165 curtime.wMilliseconds = 22;
166 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
167 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
168 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
170 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficent buffer */
171 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
172 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
174 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
175 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
176 EXPECT_VALID; EXPECT_LENA;
178 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
179 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
180 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
182 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
183 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
184 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
186 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
187 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
188 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
190 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
191 strcpy(Expected, "8:56 AM");
192 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
193 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
195 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
196 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
197 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
199 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
200 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
201 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
203 STRINGSA("t/tt", "A/AM"); /* AM time marker */
204 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
205 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
207 curtime.wHour = 13;
208 STRINGSA("t/tt", "P/PM"); /* PM time marker */
209 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
210 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
212 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
213 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
214 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
216 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
217 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
218 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
220 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
221 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
222 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
224 curtime.wHour = 14; /* change this to 14 or 2pm */
225 curtime.wMinute = 5;
226 curtime.wSecond = 3;
227 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 */
228 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
229 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
231 curtime.wHour = 0;
232 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
233 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
234 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
236 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
237 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
238 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
240 /* try to convert formatting strings with more than two letters
241 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
242 * NOTE: We expect any letter for which there is an upper case value
243 * we should see a replacement. For letters that DO NOT have
244 * upper case values we should see NO REPLACEMENT.
246 curtime.wHour = 8;
247 curtime.wMinute = 56;
248 curtime.wSecond = 13;
249 curtime.wMilliseconds = 22;
250 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
251 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
252 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
253 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
255 STRINGSA("h", "text"); /* Dont write to buffer if len is 0*/
256 strcpy(buffer, "text");
257 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
258 EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
260 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
261 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
262 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
263 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
265 STRINGSA("'''", "'"); /* invalid quoted string */
266 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
267 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
269 /* test that msdn suggested single quotation usage works as expected */
270 STRINGSA("''''", "'"); /* single quote mark */
271 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
272 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
274 STRINGSA("''HHHHHH", "08"); /* Normal use */
275 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
276 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
278 /* and test for normal use of the single quotation mark */
279 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
280 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
281 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
283 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
284 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
285 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
287 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
288 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
289 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
291 curtime.wHour = 25;
292 STRINGSA("'123'tt", ""); /* Invalid time */
293 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
294 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
296 curtime.wHour = 12;
297 curtime.wMonth = 60; /* Invalid */
298 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
299 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
300 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
303 static void test_GetDateFormatA()
305 int ret;
306 SYSTEMTIME curtime;
307 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
308 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
310 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
311 STRINGSA("ddd',' MMM dd yy","");
312 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
313 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
315 curtime.wYear = 2002;
316 curtime.wMonth = 5;
317 curtime.wDay = 4;
318 curtime.wDayOfWeek = 3;
319 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
320 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
321 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
323 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
324 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
325 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
327 curtime.wHour = 36; /* Invalid */
328 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
329 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
330 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
332 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
333 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
334 EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA;
336 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
337 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
338 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
340 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
341 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
342 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
344 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
345 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
346 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
348 /* test for expected DATE_YEARMONTH behavior with null format */
349 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
350 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
351 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
352 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
354 /* Test that using invalid DATE_* flags results in the correct error */
355 /* and return values */
356 STRINGSA("m/d/y", ""); /* Invalid flags */
357 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
358 &curtime, input, buffer, COUNTOF(buffer));
359 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA;
362 static void test_GetDateFormatW()
364 int ret;
365 SYSTEMTIME curtime;
366 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
367 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
369 STRINGSW("",""); /* If flags is not zero then format must be NULL */
370 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
371 input, buffer, COUNTOF(buffer));
372 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
373 return;
374 EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW;
376 STRINGSW("",""); /* NULL buffer, len > 0 */
377 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
378 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
380 STRINGSW("",""); /* NULL buffer, len == 0 */
381 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
382 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
384 curtime.wYear = 2002;
385 curtime.wMonth = 10;
386 curtime.wDay = 23;
387 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
388 curtime.wHour = 65432; /* Invalid */
389 curtime.wMinute = 34512; /* Invalid */
390 curtime.wSecond = 65535; /* Invalid */
391 curtime.wMilliseconds = 12345;
392 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
393 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
394 EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
398 #define CY_POS_LEFT 0
399 #define CY_POS_RIGHT 1
400 #define CY_POS_LEFT_SPACE 2
401 #define CY_POS_RIGHT_SPACE 3
403 static void test_GetCurrencyFormatA()
405 static char szDot[] = { '.', '\0' };
406 static char szComma[] = { ',', '\0' };
407 static char szDollar[] = { '$', '\0' };
408 int ret;
409 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
410 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
411 CURRENCYFMTA format;
413 memset(&format, 0, sizeof(format));
415 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
416 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
417 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
419 STRINGSA("23,53",""); /* Invalid character --> Error */
420 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
421 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
423 STRINGSA("--",""); /* Double '-' --> Error */
424 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
425 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
427 STRINGSA("0-",""); /* Trailing '-' --> Error */
428 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
429 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
431 STRINGSA("0..",""); /* Double '.' --> Error */
432 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
433 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
435 STRINGSA(" 0.1",""); /* Leading space --> Error */
436 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
437 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
439 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
440 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
441 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
443 STRINGSA("2353",""); /* Format and flags given --> Error */
444 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
445 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
447 STRINGSA("2353",""); /* Invalid format --> Error */
448 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
449 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
451 STRINGSA("2353","$2,353.00"); /* Valid number */
452 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
453 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
455 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
456 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
457 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
459 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
460 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
461 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
463 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
464 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
465 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
467 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
468 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
469 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
471 format.NumDigits = 0; /* No decimal separator */
472 format.LeadingZero = 0;
473 format.Grouping = 0; /* No grouping char */
474 format.NegativeOrder = 0;
475 format.PositiveOrder = CY_POS_LEFT;
476 format.lpDecimalSep = szDot;
477 format.lpThousandSep = szComma;
478 format.lpCurrencySymbol = szDollar;
480 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
481 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
482 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
484 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
485 STRINGSA("2353","$2353.0");
486 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
487 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
489 format.Grouping = 2; /* Group by 100's */
490 STRINGSA("2353","$23,53.0");
491 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
492 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
494 format.LeadingZero = 1; /* Always provide leading zero */
495 STRINGSA(".5","$0.5");
496 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
497 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
499 format.PositiveOrder = CY_POS_RIGHT;
500 STRINGSA("1","1.0$");
501 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
502 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
504 format.PositiveOrder = CY_POS_LEFT_SPACE;
505 STRINGSA("1","$ 1.0");
506 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
507 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
509 format.PositiveOrder = CY_POS_RIGHT_SPACE;
510 STRINGSA("1","1.0 $");
511 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
512 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
514 format.NegativeOrder = 0;
515 STRINGSA("-1","($1.0)");
516 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
517 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
519 format.NegativeOrder = 1;
520 STRINGSA("-1","-$1.0");
521 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
522 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
524 format.NegativeOrder = 2;
525 STRINGSA("-1","$-1.0");
526 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
527 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
529 format.NegativeOrder = 3;
530 STRINGSA("-1","$1.0-");
531 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
532 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
534 format.NegativeOrder = 4;
535 STRINGSA("-1","(1.0$)");
536 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
537 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
539 format.NegativeOrder = 5;
540 STRINGSA("-1","-1.0$");
541 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
542 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
544 format.NegativeOrder = 6;
545 STRINGSA("-1","1.0-$");
546 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
547 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
549 format.NegativeOrder = 7;
550 STRINGSA("-1","1.0$-");
551 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
552 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
554 format.NegativeOrder = 8;
555 STRINGSA("-1","-1.0 $");
556 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
557 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
559 format.NegativeOrder = 9;
560 STRINGSA("-1","-$ 1.0");
561 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
562 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
564 format.NegativeOrder = 10;
565 STRINGSA("-1","1.0 $-");
566 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
567 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
569 format.NegativeOrder = 11;
570 STRINGSA("-1","$ 1.0-");
571 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
572 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
574 format.NegativeOrder = 12;
575 STRINGSA("-1","$ -1.0");
576 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
577 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
579 format.NegativeOrder = 13;
580 STRINGSA("-1","1.0- $");
581 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
582 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
584 format.NegativeOrder = 14;
585 STRINGSA("-1","($ 1.0)");
586 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
587 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
589 format.NegativeOrder = 15;
590 STRINGSA("-1","(1.0 $)");
591 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
592 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
595 #define NEG_PARENS 0 /* "(1.1)" */
596 #define NEG_LEFT 1 /* "-1.1" */
597 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
598 #define NEG_RIGHT 3 /* "1.1-" */
599 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
601 static void test_GetNumberFormatA()
603 static char szDot[] = { '.', '\0' };
604 static char szComma[] = { ',', '\0' };
605 int ret;
606 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
607 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
608 NUMBERFMTA format;
610 memset(&format, 0, sizeof(format));
612 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
613 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
614 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
616 STRINGSA("23,53",""); /* Invalid character --> Error */
617 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
618 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
620 STRINGSA("--",""); /* Double '-' --> Error */
621 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
622 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
624 STRINGSA("0-",""); /* Trailing '-' --> Error */
625 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
626 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
628 STRINGSA("0..",""); /* Double '.' --> Error */
629 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
630 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
632 STRINGSA(" 0.1",""); /* Leading space --> Error */
633 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
634 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
636 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
637 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
638 EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
640 STRINGSA("2353",""); /* Format and flags given --> Error */
641 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
642 EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA;
644 STRINGSA("2353",""); /* Invalid format --> Error */
645 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
646 EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
648 STRINGSA("2353","2,353.00"); /* Valid number */
649 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
650 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
652 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
653 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
654 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
656 STRINGSA("2353.1","2,353.10"); /* Valid real number */
657 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
658 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
660 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
661 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
662 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
664 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
665 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
666 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
668 format.NumDigits = 0; /* No decimal separator */
669 format.LeadingZero = 0;
670 format.Grouping = 0; /* No grouping char */
671 format.NegativeOrder = 0;
672 format.lpDecimalSep = szDot;
673 format.lpThousandSep = szComma;
675 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
676 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
677 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
679 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
680 STRINGSA("2353","2353.0");
681 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
682 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
684 format.Grouping = 2; /* Group by 100's */
685 STRINGSA("2353","23,53.0");
686 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
687 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
689 format.LeadingZero = 1; /* Always provide leading zero */
690 STRINGSA(".5","0.5");
691 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
692 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
694 format.NegativeOrder = NEG_PARENS;
695 STRINGSA("-1","(1.0)");
696 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
697 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
699 format.NegativeOrder = NEG_LEFT;
700 STRINGSA("-1","-1.0");
701 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
702 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
704 format.NegativeOrder = NEG_LEFT_SPACE;
705 STRINGSA("-1","- 1.0");
706 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
707 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
709 format.NegativeOrder = NEG_RIGHT;
710 STRINGSA("-1","1.0-");
711 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
712 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
714 format.NegativeOrder = NEG_RIGHT_SPACE;
715 STRINGSA("-1","1.0 -");
716 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
717 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
719 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
721 if (IsValidLocale(lcid, 0))
723 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
724 Expected[3] = 160; /* Non breaking space */
725 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
726 EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
731 /* Callback function used by TestEnumTimeFormats */
732 static BOOL CALLBACK EnumTimeFormatsProc(char * lpTimeFormatString)
734 trace("%s\n", lpTimeFormatString);
735 strcpy(GlobalBuffer, lpTimeFormatString);
736 #if 0
737 return TRUE;
738 #endif
739 return FALSE;
742 void test_EnumTimeFormats()
744 int ret;
745 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
747 GlobalBuffer[0] = '\0';
748 ret = EnumTimeFormatsA(EnumTimeFormatsProc, lcid, 0);
749 ok (ret == 1 && !strcmp(GlobalBuffer,"h:mm:ss tt"), "Expected %d '%s'\n", ret, GlobalBuffer);
752 static void test_CompareStringA()
754 int ret;
755 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
757 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
758 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
760 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
761 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
763 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
764 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
766 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
767 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
769 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
771 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
772 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
774 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
775 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
777 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "SaLuT", -1);
778 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
781 void test_LCMapStringA(void)
783 int ret, ret2;
784 char buf[256], buf2[256];
785 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
786 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
787 static const char symbols_stripped[] = "justateststring1";
789 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
790 upper_case, -1, buf, sizeof(buf));
791 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
792 ok(GetLastError() == ERROR_INVALID_FLAGS,
793 "unexpected error code %ld\n", GetLastError());
795 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
796 upper_case, -1, buf, sizeof(buf));
797 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
798 ok(GetLastError() == ERROR_INVALID_FLAGS,
799 "unexpected error code %ld\n", GetLastError());
801 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
803 upper_case, -1, buf, sizeof(buf));
804 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
805 ok(GetLastError() == ERROR_INVALID_FLAGS,
806 "unexpected error code %ld\n", GetLastError());
808 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
809 upper_case, -1, buf, sizeof(buf));
810 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
811 ok(GetLastError() == ERROR_INVALID_FLAGS,
812 "unexpected error code %ld\n", GetLastError());
814 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
815 SetLastError(0xdeadbeef);
816 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
817 upper_case, -1, buf, sizeof(buf));
818 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
819 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
821 /* test LCMAP_LOWERCASE */
822 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
823 upper_case, -1, buf, sizeof(buf));
824 ok(ret == lstrlenA(upper_case) + 1,
825 "ret %d, error %ld, expected value %d\n",
826 ret, GetLastError(), lstrlenA(upper_case) + 1);
827 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
829 /* test LCMAP_UPPERCASE */
830 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
831 lower_case, -1, buf, sizeof(buf));
832 ok(ret == lstrlenA(lower_case) + 1,
833 "ret %d, error %ld, expected value %d\n",
834 ret, GetLastError(), lstrlenA(lower_case) + 1);
835 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
837 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
838 lstrcpyA(buf, lower_case);
839 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
840 buf, -1, buf, sizeof(buf));
841 if (!ret) /* Win9x */
842 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
843 else
845 ok(ret == lstrlenA(lower_case) + 1,
846 "ret %d, error %ld, expected value %d\n",
847 ret, GetLastError(), lstrlenA(lower_case) + 1);
848 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
850 lstrcpyA(buf, upper_case);
851 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
852 buf, -1, buf, sizeof(buf));
853 if (!ret) /* Win9x */
854 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
855 else
857 ok(ret == lstrlenA(upper_case) + 1,
858 "ret %d, error %ld, expected value %d\n",
859 ret, GetLastError(), lstrlenA(lower_case) + 1);
860 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
863 /* otherwise src == dst should fail */
864 SetLastError(0xdeadbeef);
865 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
866 buf, 10, buf, sizeof(buf));
867 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
868 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
869 "unexpected error code %ld\n", GetLastError());
870 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
872 /* test whether '\0' is always appended */
873 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
874 upper_case, -1, buf, sizeof(buf));
875 ok(ret, "LCMapStringA must succeed\n");
876 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
877 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
878 ok(ret, "LCMapStringA must succeed\n");
879 ok(ret == ret2, "lengths of sort keys must be equal\n");
880 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
882 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
883 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
884 upper_case, -1, buf, sizeof(buf));
885 ok(ret, "LCMapStringA must succeed\n");
886 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
887 lower_case, -1, buf2, sizeof(buf2));
888 ok(ret2, "LCMapStringA must succeed\n");
889 ok(ret == ret2, "lengths of sort keys must be equal\n");
890 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
892 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
893 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
894 lower_case, -1, buf, sizeof(buf));
895 ok(ret, "LCMapStringA must succeed\n");
896 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
897 lower_case, -1, buf2, sizeof(buf2));
898 ok(ret2, "LCMapStringA must succeed\n");
899 ok(ret == ret2, "lengths of sort keys must be equal\n");
900 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
902 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
903 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
904 lower_case, -1, buf, sizeof(buf));
905 ok(ret, "LCMapStringA must succeed\n");
906 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
907 symbols_stripped, -1, buf2, sizeof(buf2));
908 ok(ret2, "LCMapStringA must succeed\n");
909 ok(ret == ret2, "lengths of sort keys must be equal\n");
910 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
912 /* test NORM_IGNORENONSPACE */
913 lstrcpyA(buf, "foo");
914 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
915 lower_case, -1, buf, sizeof(buf));
916 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
917 lstrlenA(lower_case) + 1, ret);
918 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
920 /* test NORM_IGNORESYMBOLS */
921 lstrcpyA(buf, "foo");
922 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
923 lower_case, -1, buf, sizeof(buf));
924 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
925 lstrlenA(symbols_stripped) + 1, ret);
926 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
929 void test_LCMapStringW(void)
931 int ret, ret2;
932 WCHAR buf[256], buf2[256];
933 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
934 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};
935 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};
936 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
937 static const WCHAR fooW[] = {'f','o','o',0};
939 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
940 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
941 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
943 trace("Skipping LCMapStringW tests on Win9x\n");
944 return;
946 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
947 ok(GetLastError() == ERROR_INVALID_FLAGS,
948 "unexpected error code %ld\n", GetLastError());
950 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
951 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
952 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
953 ok(GetLastError() == ERROR_INVALID_FLAGS,
954 "unexpected error code %ld\n", GetLastError());
956 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
957 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
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 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
963 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
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 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
971 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
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 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
977 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
978 ok(ret == lstrlenW(upper_case) + 1,
979 "ret %d, error %ld, expected value %d\n",
980 ret, GetLastError(), lstrlenW(upper_case) + 1);
981 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
983 /* test LCMAP_UPPERCASE */
984 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
985 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
986 ok(ret == lstrlenW(lower_case) + 1,
987 "ret %d, error %ld, expected value %d\n",
988 ret, GetLastError(), lstrlenW(lower_case) + 1);
989 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
991 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
992 lstrcpyW(buf, lower_case);
993 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
994 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
995 ok(ret == lstrlenW(lower_case) + 1,
996 "ret %d, error %ld, expected value %d\n",
997 ret, GetLastError(), lstrlenW(lower_case) + 1);
998 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1000 lstrcpyW(buf, upper_case);
1001 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1002 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1003 ok(ret == lstrlenW(upper_case) + 1,
1004 "ret %d, error %ld, expected value %d\n",
1005 ret, GetLastError(), lstrlenW(lower_case) + 1);
1006 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1008 /* otherwise src == dst should fail */
1009 SetLastError(0xdeadbeef);
1010 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1011 buf, 10, buf, sizeof(buf));
1012 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1013 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1014 "unexpected error code %ld\n", GetLastError());
1015 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1017 /* test whether '\0' is always appended */
1018 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1019 upper_case, -1, buf, sizeof(buf));
1020 ok(ret, "LCMapStringW must succeed\n");
1021 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1022 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1023 ok(ret, "LCMapStringW must succeed\n");
1024 ok(ret == ret2, "lengths of sort keys must be equal\n");
1025 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1027 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1028 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1029 upper_case, -1, buf, sizeof(buf));
1030 ok(ret, "LCMapStringW must succeed\n");
1031 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1032 lower_case, -1, buf2, sizeof(buf2));
1033 ok(ret2, "LCMapStringW must succeed\n");
1034 ok(ret == ret2, "lengths of sort keys must be equal\n");
1035 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1037 /* test LCMAP_SORTKEY | NORM_IGNORENONSPACE */
1038 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORENONSPACE,
1039 lower_case, -1, buf, sizeof(buf));
1040 ok(ret, "LCMapStringW must succeed\n");
1041 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1042 lower_case, -1, buf2, sizeof(buf2));
1043 ok(ret2, "LCMapStringW must succeed\n");
1044 ok(ret == ret2, "lengths of sort keys must be equal\n");
1045 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1047 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1048 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1049 lower_case, -1, buf, sizeof(buf));
1050 ok(ret, "LCMapStringW must succeed\n");
1051 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1052 symbols_stripped, -1, buf2, sizeof(buf2));
1053 ok(ret2, "LCMapStringW must succeed\n");
1054 ok(ret == ret2, "lengths of sort keys must be equal\n");
1055 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1057 /* test NORM_IGNORENONSPACE */
1058 lstrcpyW(buf, fooW);
1059 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1060 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1061 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1062 lstrlenW(lower_case) + 1, ret);
1063 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1065 /* test NORM_IGNORESYMBOLS */
1066 lstrcpyW(buf, fooW);
1067 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1068 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1069 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1070 lstrlenW(symbols_stripped) + 1, ret);
1071 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1074 void test_FoldStringA(void)
1076 int ret, i;
1077 char src[256], dst[256];
1078 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1079 static const char digits_dst[] = { '1','2','3','\0' };
1080 static const char composite_src[] =
1082 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1083 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1084 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1085 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1086 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1087 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1088 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1089 0xfb,0xfc,0xfd,0xff,'\0'
1091 static const char composite_dst[] =
1093 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1094 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1095 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1096 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1097 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1098 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1099 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1100 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1101 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1102 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1103 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1104 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1105 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1106 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1107 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1109 static const char ligatures_src[] =
1111 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1113 static const char ligatures_dst[] =
1115 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1118 if (!pFoldStringA)
1119 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1121 /* MAP_FOLDDIGITS */
1122 SetLastError(0);
1123 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1124 EXPECT_LEN(4); EXPECT_VALID;
1125 ok(strcmp(dst, digits_dst) == 0,
1126 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1127 for (i = 1; i < 256; i++)
1129 if (!strchr(digits_src, i))
1131 src[0] = i;
1132 src[1] = '\0';
1133 SetLastError(0);
1134 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1135 EXPECT_LEN(2); EXPECT_VALID;
1136 ok(dst[0] == src[0],
1137 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1141 /* MAP_EXPAND_LIGATURES */
1142 SetLastError(0);
1143 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1144 EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID;
1145 ok(strcmp(dst, ligatures_dst) == 0,
1146 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1147 for (i = 1; i < 256; i++)
1149 if (!strchr(ligatures_src, i))
1151 src[0] = i;
1152 src[1] = '\0';
1153 SetLastError(0);
1154 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1155 EXPECT_LEN(2); EXPECT_VALID;
1156 ok(dst[0] == src[0],
1157 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1161 /* MAP_COMPOSITE */
1162 SetLastError(0);
1163 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1164 EXPECT_VALID;
1165 todo_wine
1167 /* Wine gets close, but doesn't produce quite the same result as native */
1168 EXPECT_LEN(121);
1169 ok(strcmp(dst, composite_dst) == 0,
1170 "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst);
1173 for (i = 1; i < 256; i++)
1175 if (!strchr(composite_src, i))
1177 src[0] = i;
1178 src[1] = '\0';
1179 SetLastError(0);
1180 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1181 EXPECT_LEN(2); EXPECT_VALID;
1182 ok(dst[0] == src[0],
1183 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1184 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1188 /* MAP_FOLDCZONE */
1189 for (i = 1; i < 256; i++)
1191 src[0] = i;
1192 src[1] = '\0';
1193 SetLastError(0);
1194 ret = FoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1195 EXPECT_LEN(2); EXPECT_VALID;
1196 ok(src[0] == dst[0],
1197 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1198 (unsigned char)src[0], (unsigned char)dst[0]);
1201 /* MAP_PRECOMPOSED */
1202 for (i = 1; i < 256; i++)
1204 src[0] = i;
1205 src[1] = '\0';
1206 SetLastError(0);
1207 ret = FoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1208 EXPECT_LEN(2); EXPECT_VALID;
1209 ok(src[0] == dst[0],
1210 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1211 (unsigned char)src[0], (unsigned char)dst[0]);
1215 void test_FoldStringW(void)
1217 int ret;
1218 size_t i, j;
1219 WCHAR src[256], dst[256], ch, prev_ch = 1;
1220 static const DWORD badFlags[] =
1223 MAP_PRECOMPOSED|MAP_COMPOSITE,
1224 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1225 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1227 /* Ranges of digits 0-9 : Must be sorted! */
1228 static const WCHAR digitRanges[] =
1230 0x0030, /* '0'-'9' */
1231 0x0660, /* Eastern Arabic */
1232 0x06F0, /* Arabic - Hindu */
1233 0x0966, /* Devengari */
1234 0x09E6, /* Bengalii */
1235 0x0A66, /* Gurmukhi */
1236 0x0AE6, /* Gujarati */
1237 0x0B66, /* Oriya */
1238 0x0BE6, /* Tamil - No 0 */
1239 0x0C66, /* Telugu */
1240 0x0CE6, /* Kannada */
1241 0x0D66, /* Maylayalam */
1242 0x0E50, /* Thai */
1243 0x0ED0, /* Laos */
1244 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1245 0x2080, /* Subscript */
1246 0x245F, /* Circled - 0 is out of sequence */
1247 0x2473, /* Bracketed */
1248 0x2487, /* Full stop */
1249 0x2775, /* Inverted circled - No 0 */
1250 0x277F, /* Patterned circled - No 0 */
1251 0x2789, /* Inverted Patterned circled - No 0 */
1252 0xff10, /* Pliene chasse (?) */
1253 0xffff /* Terminator */
1255 /* Digits which are represented, but out of sequence */
1256 static const WCHAR outOfSequenceDigits[] =
1258 0xB9, /* Superscript 1 */
1259 0xB2, /* Superscript 2 */
1260 0xB3, /* Superscript 3 */
1261 0x24EA, /* Circled 0 */
1262 '\0' /* Terminator */
1264 /* Digits in digitRanges for which no representation is available */
1265 static const WCHAR noDigitAvailable[] =
1267 0x0BE6, /* No Tamil 0 */
1268 0x2473, /* No Bracketed 0 */
1269 0x2487, /* No 0 Full stop */
1270 0x2775, /* No inverted circled 0 */
1271 0x277F, /* No patterned circled */
1272 0x2789, /* No inverted Patterned circled */
1273 '\0' /* Terminator */
1275 /* Compatibility conversion results */
1276 static const WCHAR compat_F900_FA2F[256+48] =
1278 0x8c48, 0x66f4, 0x8eca, 0x8cc8, 0x6ed1, 0x4e32, 0x53e5, 0x9f9c,
1279 0x9f9c, 0x5951, 0x91d1, 0x5587, 0x5948, 0x61f6, 0x7669, 0x7f85,
1280 0x863f, 0x87ba, 0x88f8, 0x908f, 0x6a02, 0x6d1b, 0x70d9, 0x73de,
1281 0x843d, 0x916a, 0x99f1, 0x4e82, 0x5375, 0x6b04, 0x721b, 0x862d,
1282 0x9e1e, 0x5d50, 0x6feb, 0x85cd, 0x8964, 0x62c9, 0x81d8, 0x881f,
1283 0x5eca, 0x6717, 0x6d6a, 0x72fc, 0x0000, 0x4f86, 0x51b7, 0x52de,
1284 0x64c4, 0x6ad3, 0x7210, 0x76e7, 0x8001, 0x8606, 0x865c, 0x8def,
1285 0x9732, 0x9b6f, 0x9dfa, 0x788c, 0x797f, 0x7da0, 0x83c9, 0x9304,
1286 0x9e7f, 0x8ad6, 0x58df, 0x5f04, 0x7c60, 0x807e, 0x7262, 0x78ca,
1287 0x8cc2, 0x96f7, 0x58d8, 0x5c62, 0x6a13, 0x6dda, 0x6f0f, 0x7d2f,
1288 0x7e37, 0x964b, 0x52d2, 0x808b, 0x51dc, 0x51cc, 0x7a1c, 0x7dbe,
1289 0x83f1, 0x9675, 0x8b80, 0x62cf, 0x6a02, 0x8afe, 0x4e39, 0x5be7,
1290 0x6012, 0x7387, 0x7570, 0x5317, 0x78fb, 0x4fbf, 0x5fa9, 0x4e0d,
1291 0x6ccc, 0x6578, 0x7d22, 0x53c3, 0x585e, 0x7701, 0x8449, 0x8aaa,
1292 0x6bba, 0x8fb0, 0x6c88, 0x62fe, 0x82e5, 0x63a0, 0x7565, 0x4eae,
1293 0x5169, 0x0000, 0x6881, 0x7ce7, 0x826f, 0x8ad2, 0x91cf, 0x52f5,
1294 0x5442, 0x5973, 0x5eec, 0x65c5, 0x6ffe, 0x792a, 0x95ad, 0x9a6a,
1295 0x9e97, 0x9ece, 0x529b, 0x66c6, 0x6b77, 0x8f62, 0x5e74, 0x6190,
1296 0x6200, 0x649a, 0x6f23, 0x7149, 0x7489, 0x0000, 0x7df4, 0x806f,
1297 0x8f26, 0x84ee, 0x9023, 0x934a, 0x5217, 0x52a3, 0x54bd, 0x70c8,
1298 0x88c2, 0x8aaa, 0x5ec9, 0x5ff5, 0x637b, 0x6bae, 0x7c3e, 0x7375,
1299 0x4ee4, 0x56f9, 0x5be7, 0x5dba, 0x601c, 0x73b2, 0x7469, 0x7f9a,
1300 0x8046, 0x9234, 0x96f6, 0x9748, 0x9818, 0x4f8b, 0x79ae, 0x91b4,
1301 0x96b8, 0x60e1, 0x4e86, 0x50da, 0x5bee, 0x5c3f, 0x6599, 0x6a02,
1302 0x71ce, 0x7642, 0x84fc, 0x907c, 0x9f8d, 0x6688, 0x962e, 0x5289,
1303 0x677b, 0x67f3, 0x6d41, 0x6e9c, 0x7409, 0x7559, 0x786b, 0x7d10,
1304 0x985e, 0x516d, 0x622e, 0x9678, 0x502b, 0x5d19, 0x6dea, 0x8f2a,
1305 0x5f8b, 0x6144, 0x6817, 0x7387, 0x9686, 0x5229, 0x540f, 0x5c65,
1306 0x6613, 0x674e, 0x68a8, 0x6ce5, 0x7406, 0x75e2, 0x7f79, 0x0000,
1307 0x88e1, 0x91cc, 0x96e2, 0x533f, 0x6eba, 0x541d, 0x71d0, 0x7498,
1308 0x85fa, 0x0000, 0x9c57, 0x9e9f, 0x6797, 0x6dcb, 0x81e8, 0x7acb,
1309 0x7b20, 0x7c92, 0x72c0, 0x7099, 0x8b58, 0x4ec0, 0x8336, 0x523a,
1310 0x5207, 0x5ea6, 0x62d3, 0x7cd6, 0x5b85, 0x6d1e, 0x66b4, 0x8f3b,
1311 0x884c, 0x964d, 0x898b, 0x5ed3, 0x0000, 0x0000, 0x0000, 0x0000,
1312 0x585a, 0x0000, 0x6674, 0x0000, 0x0000, 0x51de, 0x8c6c, 0x76ca,
1313 0x0000, 0x795e, 0x7965, 0x798f, 0x9756, 0x7cbe, 0x7fbd, 0x0000,
1314 0x0000, 0x0000, 0x8af8, 0x0000, 0x0000, 0x9038, 0x90fd, 0x0000,
1315 0x0000, 0x0000, 0x98ef, 0x98fc, 0x9928, 0x9db4, 0x0000, 0x0000
1317 static const WCHAR compat_FE30_FEF7[200] =
1319 0x2025, 0x2014, 0x2013, 0x005f, 0x005f, 0x0028, 0x0029, 0x007b,
1320 0x007d, 0x3014, 0x3015, 0x3010, 0x3011, 0x300a, 0x300b, 0x3008,
1321 0x3009, 0x300c, 0x300d, 0x300e, 0x300f, 0x0000, 0x0000, 0x0000,
1322 0x0000, 0x203e, 0x203e, 0x203e, 0x203e, 0x005f, 0x005f, 0x005f,
1323 0x002c, 0x3001, 0x002e, 0x0000, 0x003b, 0x003a, 0x003f, 0x0021,
1324 0x2014, 0x0028, 0x0029, 0x007b, 0x007d, 0x3014, 0x3015, 0x0023,
1325 0x0026, 0x002a, 0x002b, 0x002d, 0x003c, 0x003e, 0x003d, 0x0000,
1326 0x0000, 0x0024, 0x0025, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000,
1327 0x064b, 0x064b, 0x064c, 0x0000, 0x064d, 0x0000, 0x064e, 0x064e,
1328 0x064f, 0x064f, 0x0650, 0x0650, 0x0651, 0x0651, 0x0652, 0x0652,
1329 0x0621, 0x0622, 0x0622, 0x0623, 0x0623, 0x0624, 0x0624, 0x0625,
1330 0x0625, 0x0626, 0x0626, 0x0626, 0x0626, 0x0627, 0x0627, 0x0628,
1331 0x0628, 0x0628, 0x0628, 0x0629, 0x0629, 0x062a, 0x062a, 0x062a,
1332 0x062a, 0x062b, 0x062b, 0x062b, 0x062b, 0x062c, 0x062c, 0x062c,
1333 0x062c, 0x062d, 0x062d, 0x062d, 0x062d, 0x062e, 0x062e, 0x062e,
1334 0x062e, 0x062f, 0x062f, 0x0630, 0x0630, 0x0631, 0x0631, 0x0632,
1335 0x0632, 0x0633, 0x0633, 0x0633, 0x0633, 0x0634, 0x0634, 0x0634,
1336 0x0634, 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, 0x0636, 0x0636,
1337 0x0636, 0x0637, 0x0637, 0x0637, 0x0637, 0x0638, 0x0638, 0x0638,
1338 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, 0x063a, 0x063a, 0x063a,
1339 0x063a, 0x0641, 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, 0x0642,
1340 0x0642, 0x0643, 0x0643, 0x0643, 0x0643, 0x0644, 0x0644, 0x0644,
1341 0x0644, 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, 0x0646, 0x0646,
1342 0x0646, 0x0647, 0x0647, 0x0647, 0x0647, 0x0648, 0x0648, 0x0649,
1343 0x0649, 0x064a, 0x064a, 0x064a, 0x064a, 0x0000, 0x0000, 0x0000
1345 static const WCHAR compat_FF00_FFEF[240] =
1347 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
1348 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
1349 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
1350 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
1351 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
1352 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
1353 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
1354 0x0058, 0x0059, 0x005a, 0x005b, 0x0000, 0x005d, 0x005e, 0x005f,
1355 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
1356 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
1357 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
1358 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
1359 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb, 0x30f2, 0x30a1,
1360 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3,
1361 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad,
1362 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd,
1363 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc,
1364 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de,
1365 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9,
1366 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c,
1367 0x3164, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137,
1368 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f,
1369 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147,
1370 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x0000,
1371 0x0000, 0x0000, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154,
1372 0x0000, 0x0000, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a,
1373 0x0000, 0x0000, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
1374 0x0000, 0x0000, 0x3161, 0x3162, 0x3163, 0x0000, 0x0000, 0x0000,
1375 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9, 0x0000,
1376 0x2502, 0x2190, 0x2191, 0x2192, 0x2193, 0x25a0, 0x25cb, 0x0000
1378 static const WCHAR ligatures_src[] =
1380 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1381 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1382 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1383 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
1384 0xfb04, 0xfb05, 0xfb06, '\0'
1386 static const WCHAR ligatures_dst[] =
1388 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
1389 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
1390 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
1391 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
1392 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
1395 if (!pFoldStringW)
1396 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1398 /* Invalid flag combinations */
1399 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1401 src[0] = dst[0] = '\0';
1402 SetLastError(0);
1403 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1404 EXPECT_LEN(0); EXPECT_FLAGS;
1407 /* src & dst cannot be the same */
1408 SetLastError(0);
1409 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
1410 EXPECT_LEN(0); EXPECT_INVALID;
1412 /* src can't be NULL */
1413 SetLastError(0);
1414 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1415 EXPECT_LEN(0); EXPECT_INVALID;
1417 /* srclen can't be 0 */
1418 SetLastError(0);
1419 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1420 EXPECT_LEN(0); EXPECT_INVALID;
1422 /* dstlen can't be < 0 */
1423 SetLastError(0);
1424 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1425 EXPECT_LEN(0); EXPECT_INVALID;
1427 /* Ret includes terminating NUL which is appended if srclen = -1 */
1428 SetLastError(0);
1429 src[0] = 'A';
1430 src[1] = '\0';
1431 dst[0] = '\0';
1432 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1433 EXPECT_LEN(2); EXPECT_VALID;
1434 ok(dst[0] == 'A' && dst[1] == '\0',
1435 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%ld\n",
1436 'A', '\0', ret, dst[0], dst[1], GetLastError());
1438 /* If size is given, result is not NUL terminated */
1439 SetLastError(0);
1440 src[0] = 'A';
1441 src[1] = 'A';
1442 dst[0] = 'X';
1443 dst[1] = 'X';
1444 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
1445 EXPECT_LEN(1); EXPECT_VALID;
1446 ok(dst[0] == 'A' && dst[1] == 'X',
1447 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%ld\n",
1448 'A','X', ret, dst[0], dst[1], GetLastError());
1450 /* MAP_FOLDDIGITS */
1451 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1453 /* Check everything before this range */
1454 for (ch = prev_ch; ch < digitRanges[j]; ch++)
1456 SetLastError(0);
1457 src[0] = ch;
1458 src[1] = dst[0] = '\0';
1459 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1460 EXPECT_LEN(2); EXPECT_VALID;
1462 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
1463 /* Wine (correctly) maps all Unicode 4.0+ digits */
1464 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF,
1465 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
1468 if (digitRanges[j] == 0xffff)
1469 break; /* Finished the whole code point space */
1471 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1473 WCHAR c;
1475 /* Map out of sequence characters */
1476 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
1477 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
1478 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
1479 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
1480 else c = ch;
1481 SetLastError(0);
1482 src[0] = c;
1483 src[1] = dst[0] = '\0';
1484 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
1485 EXPECT_LEN(2); EXPECT_VALID;
1487 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
1488 strchrW(noDigitAvailable, c),
1489 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
1490 ch, '0' + digitRanges[j] - ch, dst[0]);
1492 prev_ch = ch;
1495 /* MAP_FOLDCZONE */
1496 for (ch = 1; ch <0xffff; ch++)
1498 WCHAR expected = 0;
1500 if (ch >= 0xF900 && ch <= 0xFA2F)
1501 expected = compat_F900_FA2F[ch - 0xF900];
1502 else if (ch >= 0xFE30 && ch <= 0xFEF7)
1503 expected = compat_FE30_FEF7[ch - 0xFE30];
1504 else if (ch >= 0xFF00 && ch <= 0xFFEF)
1505 expected = compat_FF00_FFEF[ch - 0xFF00];
1507 if (!expected)
1508 expected = ch;
1510 SetLastError(0);
1511 src[0] = ch;
1512 src[1] = dst[0] = '\0';
1513 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
1514 EXPECT_LEN(2); EXPECT_VALID;
1515 ok(dst[0] == expected ||
1516 /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */
1517 (ch >= 0xFA0D && ch <= 0xFA47) ||
1518 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || ch == 0xf9f1,
1519 "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n",
1520 ch, ch, expected, dst[0]);
1523 /* MAP_EXPAND_LIGATURES */
1524 SetLastError(0);
1525 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1526 EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID;
1527 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
1528 "MAP_EXPAND_LIGATURES: Expanded incorrrectly\n");
1529 for (i = 1; i <= 0xffff; i++)
1531 if (!strchrW(ligatures_src, i))
1533 src[0] = i;
1534 src[1] = '\0';
1535 SetLastError(0);
1536 ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1537 EXPECT_LEN(2); EXPECT_VALID;
1538 ok(dst[0] == src[0],
1539 "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n",
1540 i, src[0], dst[0]);
1544 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1549 #define LCID_OK(l) \
1550 ok(lcid == l, "Expected lcid = %08lx, got %08lx\n", l, lcid)
1551 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
1552 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
1553 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
1554 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
1556 static void test_ConvertDefaultLocale(void)
1558 LCID lcid;
1560 /* Doesn't change lcid, even if non default sublang/sort used */
1561 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
1562 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
1563 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
1564 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
1566 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
1567 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
1568 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
1569 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
1570 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
1571 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_JAPANESE_UNICODE),
1572 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE));
1574 /* Invariant language is not treated specially */
1575 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
1576 LCID_RES(MKLCID(LANG_INVARIANT, SUBLANG_NEUTRAL, SORT_DEFAULT),
1577 MKLCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT));
1579 /* User/system default languages alone are not mapped */
1580 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
1581 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
1583 /* Default lcids */
1584 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
1585 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
1586 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
1589 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
1590 DWORD dwFlags, LONG_PTR lParam)
1592 trace("%08lx, %s, %s, %08lx, %08lx\n",
1593 lgrpid, lpszNum, lpszName, dwFlags, lParam);
1595 ok(IsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
1596 "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
1598 /* If lParam is one, we are calling with flags defaulted from 0 */
1599 ok(!lParam || dwFlags == LGRPID_INSTALLED,
1600 "Expected dwFlags == LGRPID_INSTALLED, got %ld\n", dwFlags);
1602 return TRUE;
1605 static void test_EnumSystemLanguageGroupsA(void)
1607 if (!pEnumSystemLanguageGroupsA)
1608 return;
1610 /* No enumeration proc */
1611 SetLastError(0);
1612 pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
1613 EXPECT_INVALID;
1615 /* Invalid flags */
1616 SetLastError(0);
1617 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
1618 EXPECT_FLAGS;
1620 /* No flags - defaults to LGRPID_INSTALLED */
1621 SetLastError(0);
1622 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
1623 EXPECT_VALID;
1625 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
1626 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
1630 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
1631 LONG_PTR lParam)
1633 trace("%08lx, %08lx, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
1635 ok(IsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
1636 "Enumerated grp %ld not valid\n", lgrpid);
1637 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
1638 "Enumerated grp locale %ld not valid\n", lcid);
1639 return TRUE;
1642 static void test_EnumLanguageGroupLocalesA(void)
1644 if (!pEnumLanguageGroupLocalesA)
1645 return;
1647 /* No enumeration proc */
1648 SetLastError(0);
1649 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
1650 EXPECT_INVALID;
1652 /* lgrpid too small */
1653 SetLastError(0);
1654 pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
1655 EXPECT_INVALID;
1657 /* lgrpid too big */
1658 SetLastError(0);
1659 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
1660 EXPECT_INVALID;
1662 /* dwFlags is reserved */
1663 SetLastError(0);
1664 pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
1665 EXPECT_INVALID;
1667 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
1670 static void test_SetLocaleInfoA(void)
1672 BOOL bRet;
1673 LCID lcid = GetUserDefaultLCID();
1675 /* Null data */
1676 SetLastError(0);
1677 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
1678 EXPECT_INVALID;
1680 /* IDATE */
1681 SetLastError(0);
1682 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
1683 EXPECT_FLAGS;
1685 /* ILDATE */
1686 SetLastError(0);
1687 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
1688 EXPECT_FLAGS;
1691 START_TEST(locale)
1693 InitFunctionPointers();
1695 #if 0
1696 test_EnumTimeFormats();
1697 #endif
1698 test_GetLocaleInfoA();
1699 test_GetTimeFormatA();
1700 test_GetDateFormatA();
1701 test_GetDateFormatW();
1702 test_GetCurrencyFormatA(); /* Also tests the W version */
1703 test_GetNumberFormatA(); /* Also tests the W version */
1704 test_CompareStringA();
1705 test_LCMapStringA();
1706 test_LCMapStringW();
1707 test_FoldStringA();
1708 test_FoldStringW();
1709 test_ConvertDefaultLocale();
1710 test_EnumSystemLanguageGroupsA();
1711 test_EnumLanguageGroupLocalesA();
1712 test_SetLocaleInfoA();