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