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