If using the default values, also set dwType to REG_SZ as our default
[wine] / dlls / kernel / tests / locale.c
1 /*
2  * Unit tests for locale functions
3  *
4  * Copyright 2002 YASAR Mehmet
5  * Copyright 2003 Dmitry Timoshkov
6  * Copyright 2003 Jon Griffiths
7  *
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.
12  *
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.
17  *
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
21  *
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.
26  */
27 #include <stdarg.h>
28
29 #include "wine/test.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winnls.h"
34
35 static inline unsigned int strlenW( const WCHAR *str )
36 {
37     const WCHAR *s = str;
38     while (*s) s++;
39     return s - str;
40 }
41
42 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
43 {
44     if (n <= 0) return 0;
45     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
46     return *str1 - *str2;
47 }
48
49 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
50 {
51     for ( ; *str; str++) if (*str == ch) return (WCHAR *)str;
52     return NULL;
53 }
54
55 inline static int isdigitW( WCHAR wc )
56 {
57     WORD type;
58     GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
59     return type & C1_DIGIT;
60 }
61
62 /* Some functions are only in later versions of kernel32.dll */
63 static HMODULE hKernel32;
64
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;
71
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;
76
77 static void InitFunctionPointers(void)
78 {
79   hKernel32 = GetModuleHandleA("kernel32");
80
81   if (hKernel32)
82   {
83     pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
84     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
85     pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
86     pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
87   }
88 }
89
90 #define eq(received, expected, label, type) \
91         ok((received) == (expected), "%s: got " type " instead of " type "\n", \
92            (label), (received), (expected))
93
94 #define BUFFER_SIZE    128
95 char GlobalBuffer[BUFFER_SIZE]; /* Buffer used by callback function */
96 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
97
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())
110
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)
115
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")
121
122 #define NUO LOCALE_NOUSEROVERRIDE
123
124 static void test_GetLocaleInfoA()
125 {
126   int ret;
127   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
128   char buffer[BUFFER_SIZE];
129
130   ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
131
132   /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
133    * partially fill the buffer even if it is too short. See bug 637.
134    */
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);
138
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);
143
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);
148 }
149
150 static void test_GetTimeFormatA()
151 {
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];
156
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;
161
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;
169
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;
173
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;
177
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;
181
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;
185
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;
189
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;
194
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;
198
199   STRINGSA("s1s2s3", ""); /* Duplicate tokens */
200   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
201   EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
202
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;
206
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;
211
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;
215
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;
219
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;
223
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;
230
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;
235
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;
239
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.
245    */
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;
254
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;
259
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;
264
265   STRINGSA("'''", "'"); /* invalid quoted string */
266   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
267   EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
268
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;
273
274   STRINGSA("''HHHHHH", "08"); /* Normal use */
275   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
276   EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
277
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;
282
283   STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
284   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
285   EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
286
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;
290
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;
295
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;
301 }
302
303 static void test_GetDateFormatA()
304 {
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];
309
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;
314
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;
322
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;
326
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;
331
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;
335
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;
339
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;
343
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;
347
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;
353
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;
360 }
361
362 static void test_GetDateFormatW()
363 {
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);
368
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;
375
376   STRINGSW("",""); /* NULL buffer, len > 0 */
377   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
378   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW;
379
380   STRINGSW("",""); /* NULL buffer, len == 0 */
381   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
382   EXPECT_VALID; EXPECT_LENW; EXPECT_EQW;
383
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;
395 }
396
397
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
402
403 static void test_GetCurrencyFormatA()
404 {
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;
412
413   memset(&format, 0, sizeof(format));
414
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;
418
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;
422
423   STRINGSA("--",""); /* Double '-' --> Error */
424   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
425   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
426
427   STRINGSA("0-",""); /* Trailing '-' --> Error */
428   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
429   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
430
431   STRINGSA("0..",""); /* Double '.' --> Error */
432   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
433   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
434
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;
438
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;
442
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;
446
447   STRINGSA("2353",""); /* Invalid format --> Error */
448   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
449   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
450
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;
454
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;
458
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;
462
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;
466
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;
470
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;
479
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;
483
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;
488
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;
493
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;
498
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;
503
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;
508
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;
513
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;
518
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;
523
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;
528
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;
533
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;
538
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;
543
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;
548
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;
553
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;
558
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;
563
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;
568
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;
573
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;
578
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;
583
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;
588
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;
593 }
594
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 -" */
600
601 static void test_GetNumberFormatA()
602 {
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;
609
610   memset(&format, 0, sizeof(format));
611
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;
615
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;
619
620   STRINGSA("--",""); /* Double '-' --> Error */
621   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
622   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
623
624   STRINGSA("0-",""); /* Trailing '-' --> Error */
625   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
626   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
627
628   STRINGSA("0..",""); /* Double '.' --> Error */
629   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
630   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
631
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;
635
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;
639
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;
643
644   STRINGSA("2353",""); /* Invalid format --> Error */
645   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
646   EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
647
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;
651
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;
655
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;
659
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;
663
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;
667
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;
674
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;
678
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;
683
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;
688
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;
693
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;
698
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;
703
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;
708
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;
713
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;
718
719   lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
720
721   if (IsValidLocale(lcid, 0))
722   {
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;
727   }
728 }
729
730
731 /* Callback function used by TestEnumTimeFormats */
732 static BOOL CALLBACK EnumTimeFormatsProc(char * lpTimeFormatString)
733 {
734   trace("%s\n", lpTimeFormatString);
735   strcpy(GlobalBuffer, lpTimeFormatString);
736 #if 0
737   return TRUE;
738 #endif
739   return FALSE;
740 }
741
742 void test_EnumTimeFormats()
743 {
744   int ret;
745   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
746
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);
750 }
751
752 static void test_CompareStringA()
753 {
754   int ret;
755   LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
756
757   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
758   ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
759
760   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
761   ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
762
763   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
764   ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
765
766   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
767   ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
768
769   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
770
771   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
772   ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
773
774   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
775   ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
776
777   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "SaLuT", -1);
778   ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
779 }
780
781 void test_LCMapStringA(void)
782 {
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";
788
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());
794
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());
800
801     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
802
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());
807
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());
813
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");
820
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);
828
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);
836
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
844     {
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);
849     }
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
856     {
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);
861     }
862
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");
871
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");
881
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");
891
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");
901
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");
911
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);
919
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);
927 }
928
929 void test_LCMapStringW(void)
930 {
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};
938
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)
942     {
943         trace("Skipping LCMapStringW tests on Win9x\n");
944         return;
945     }
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());
949
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());
955
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());
961
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());
967
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");
974
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");
982
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");
990
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");
999
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");
1007
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");
1016
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");
1026
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");
1036
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");
1046
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");
1056
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");
1064
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");
1072 }
1073
1074 void test_FoldStringA(void)
1075 {
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[] =
1081   {
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'
1090   };
1091   static const char composite_dst[] =
1092   {
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'
1108   };
1109   static const char ligatures_src[] =
1110   {
1111     0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1112   };
1113   static const char ligatures_dst[] =
1114   {
1115     'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1116   };
1117
1118   if (!pFoldStringA)
1119     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1120
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++)
1128   {
1129     if (!strchr(digits_src, i))
1130     {
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);
1138     }
1139   }
1140
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++)
1148   {
1149     if (!strchr(ligatures_src, i))
1150     {
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);
1158     }
1159   }
1160
1161   /* MAP_COMPOSITE */
1162   SetLastError(0);
1163   ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1164   EXPECT_VALID;
1165   todo_wine
1166   {
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);
1171   }
1172
1173   for (i = 1; i < 256; i++)
1174   {
1175     if (!strchr(composite_src, i))
1176     {
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]);
1185     }
1186   }
1187
1188   /* MAP_FOLDCZONE */
1189   for (i = 1; i < 256; i++)
1190   {
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]);
1199   }
1200
1201   /* MAP_PRECOMPOSED */
1202   for (i = 1; i < 256; i++)
1203   {
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]);
1212   }
1213 }
1214
1215 void test_FoldStringW(void)
1216 {
1217   int ret;
1218   size_t i, j;
1219   WCHAR src[256], dst[256], ch, prev_ch = 1;
1220   static const DWORD badFlags[] =
1221   {
1222     0,
1223     MAP_PRECOMPOSED|MAP_COMPOSITE,
1224     MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1225     MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1226   };
1227   /* Ranges of digits 0-9 : Must be sorted! */
1228   static const WCHAR digitRanges[] =
1229   {
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 */
1254   };
1255   /* Digits which are represented, but out of sequence */
1256   static const WCHAR outOfSequenceDigits[] =
1257   {
1258       0xB9,   /* Superscript 1 */
1259       0xB2,   /* Superscript 2 */
1260       0xB3,   /* Superscript 3 */
1261       0x24EA, /* Circled 0 */
1262       '\0'    /* Terminator */
1263   };
1264   /* Digits in digitRanges for which no representation is available */
1265   static const WCHAR noDigitAvailable[] =
1266   {
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 */
1274   };
1275   /* Compatibility conversion results */
1276   static const WCHAR compat_F900_FA2F[256+48] =
1277   {
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
1316   };
1317   static const WCHAR compat_FE30_FEF7[200] =
1318   {
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
1344   };
1345   static const WCHAR compat_FF00_FFEF[240] =
1346   {
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
1377   };
1378   static const WCHAR ligatures_src[] =
1379   {
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'
1385   };
1386   static const WCHAR ligatures_dst[] =
1387   {
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'
1393   };
1394
1395   if (!pFoldStringW)
1396     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1397
1398   /* Invalid flag combinations */
1399   for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
1400   {
1401     src[0] = dst[0] = '\0';
1402     SetLastError(0);
1403     ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
1404     EXPECT_LEN(0); EXPECT_FLAGS;
1405   }
1406
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;
1411
1412   /* src can't be NULL */
1413   SetLastError(0);
1414   ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
1415   EXPECT_LEN(0); EXPECT_INVALID;
1416
1417   /* srclen can't be 0 */
1418   SetLastError(0);
1419   ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
1420   EXPECT_LEN(0); EXPECT_INVALID;
1421
1422   /* dstlen can't be < 0 */
1423   SetLastError(0);
1424   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
1425   EXPECT_LEN(0); EXPECT_INVALID;
1426
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());
1437
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());
1449
1450   /* MAP_FOLDDIGITS */
1451   for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
1452   {
1453     /* Check everything before this range */
1454     for (ch = prev_ch; ch < digitRanges[j]; ch++)
1455     {
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;
1461
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]);
1466     }
1467
1468     if (digitRanges[j] == 0xffff)
1469       break; /* Finished the whole code point space */
1470
1471     for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
1472     {
1473       WCHAR c;
1474
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;
1486
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]);
1491     }
1492     prev_ch = ch;
1493   }
1494
1495   /* MAP_FOLDCZONE */
1496   for (ch = 1; ch <0xffff; ch++)
1497   {
1498     WCHAR expected = 0;
1499
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];
1506
1507     if (!expected)
1508       expected = ch;
1509
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]);
1521   }
1522
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++)
1530   {
1531     if (!strchrW(ligatures_src, i))
1532     {
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]);
1541     }
1542   }
1543
1544   /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
1545 }
1546
1547
1548
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))
1555
1556 static void test_ConvertDefaultLocale(void)
1557 {
1558   LCID lcid;
1559
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);
1565
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));
1573
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));
1578
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);
1582
1583   /* Default lcids */
1584   LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
1585   LCID_RES(LOCALE_USER_DEFAULT,   GetUserDefaultLCID());
1586   LCID_RES(LOCALE_NEUTRAL,        GetUserDefaultLCID());
1587 }
1588
1589 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
1590                                     DWORD dwFlags, LONG_PTR lParam)
1591 {
1592   trace("%08lx, %s, %s, %08lx, %08lx\n",
1593         lgrpid, lpszNum, lpszName, dwFlags, lParam);
1594
1595   ok(IsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
1596      "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
1597
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);
1601
1602   return TRUE;
1603 }
1604
1605 static void test_EnumSystemLanguageGroupsA(void)
1606 {
1607   if (!pEnumSystemLanguageGroupsA)
1608     return;
1609
1610   /* No enumeration proc */
1611   SetLastError(0);
1612   pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
1613   EXPECT_INVALID;
1614
1615   /* Invalid flags */
1616   SetLastError(0);
1617   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
1618   EXPECT_FLAGS;
1619
1620   /* No flags - defaults to LGRPID_INSTALLED */
1621   SetLastError(0);
1622   pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
1623   EXPECT_VALID;
1624
1625   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
1626   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
1627 }
1628
1629
1630 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
1631                                       LONG_PTR lParam)
1632 {
1633   trace("%08lx, %08lx, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
1634
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;
1640 }
1641
1642 static void test_EnumLanguageGroupLocalesA(void)
1643 {
1644   if (!pEnumLanguageGroupLocalesA)
1645    return;
1646
1647   /* No enumeration proc */
1648   SetLastError(0);
1649   pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
1650   EXPECT_INVALID;
1651
1652   /* lgrpid too small */
1653   SetLastError(0);
1654   pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
1655   EXPECT_INVALID;
1656
1657   /* lgrpid too big */
1658   SetLastError(0);
1659   pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
1660   EXPECT_INVALID;
1661
1662   /* dwFlags is reserved */
1663   SetLastError(0);
1664   pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
1665   EXPECT_INVALID;
1666
1667   pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
1668 }
1669
1670 static void test_SetLocaleInfoA(void)
1671 {
1672   BOOL bRet;
1673   LCID lcid = GetUserDefaultLCID();
1674
1675   /* Null data */
1676   SetLastError(0);
1677   bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
1678   EXPECT_INVALID;
1679
1680   /* IDATE */
1681   SetLastError(0);
1682   bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
1683   EXPECT_FLAGS;
1684
1685   /* ILDATE */
1686   SetLastError(0);
1687   bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
1688   EXPECT_FLAGS;
1689 }
1690
1691 START_TEST(locale)
1692 {
1693   InitFunctionPointers();
1694
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();
1713 }