mshtml: Keep reference in node returned from get_node.
[wine] / dlls / kernel32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #include <stdio.h>
32
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38
39 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};
40 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};
41 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
42 static const WCHAR fooW[] = {'f','o','o',0};
43
44 static inline unsigned int strlenW( const WCHAR *str )
45 {
46     const WCHAR *s = str;
47     while (*s) s++;
48     return s - str;
49 }
50
51 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
52 {
53     if (n <= 0) return 0;
54     while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
55     return *str1 - *str2;
56 }
57
58 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
59 {
60     do { if (*str == ch) return (WCHAR *)str; } while (*str++);
61     return NULL;
62 }
63
64 static inline int isdigitW( WCHAR wc )
65 {
66     WORD type;
67     GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
68     return type & C1_DIGIT;
69 }
70
71 /* Some functions are only in later versions of kernel32.dll */
72 static HMODULE hKernel32;
73 static WORD enumCount;
74
75 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
76 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
77 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
78 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
79 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
80 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
81 static INT  (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
82 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
83 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
84 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
85 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
86 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
87 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88
89 static void InitFunctionPointers(void)
90 {
91   hKernel32 = GetModuleHandleA("kernel32");
92   pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
93   pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
94   pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
95   pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
96   pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
97   pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
98   pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
99   pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
100   pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
101   pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
102   pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
103   pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
104   pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
105 }
106
107 #define eq(received, expected, label, type) \
108         ok((received) == (expected), "%s: got " type " instead of " type "\n", \
109            (label), (received), (expected))
110
111 #define BUFFER_SIZE    128
112 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
113
114 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
115 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
116 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
117   "Expected '%s', got '%s'\n", 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(0xdeadbeef); buffer[0] = '\0'
122 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
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(void)
128 {
129   int ret;
130   int len;
131   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
132   char buffer[BUFFER_SIZE];
133   char expected[BUFFER_SIZE];
134
135   ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
136
137   /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
138      Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
139      assumes SUBLANG_NEUTRAL for zh */
140   memset(expected, 0, COUNTOF(expected));
141   len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
142   SetLastError(0xdeadbeef);
143   memset(buffer, 0, COUNTOF(buffer));
144   ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
145   ok((ret == len) && !lstrcmpA(buffer, expected),
146       "got %d with '%s' (expected %d with '%s')\n",
147       ret, buffer, len, expected);
148
149   memset(expected, 0, COUNTOF(expected));
150   len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
151   if (len) {
152       SetLastError(0xdeadbeef);
153       memset(buffer, 0, COUNTOF(buffer));
154       ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
155       ok((ret == len) && !lstrcmpA(buffer, expected),
156           "got %d with '%s' (expected %d with '%s')\n",
157           ret, buffer, len, expected);
158   }
159   else
160       win_skip("LANG_ARABIC not installed\n");
161
162   /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
163   memset(expected, 0, COUNTOF(expected));
164   len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
165   SetLastError(0xdeadbeef);
166   memset(buffer, 0, COUNTOF(buffer));
167   ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
168   ok((ret == len) && !lstrcmpA(buffer, expected),
169       "got %d with '%s' (expected %d with '%s')\n",
170       ret, buffer, len, expected);
171
172
173   /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
174    * partially fill the buffer even if it is too short. See bug 637.
175    */
176   SetLastError(0xdeadbeef);
177   memset(buffer, 0, COUNTOF(buffer));
178   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
179   ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
180
181   SetLastError(0xdeadbeef);
182   memset(buffer, 0, COUNTOF(buffer));
183   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
184   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
185       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
186   ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
187
188   SetLastError(0xdeadbeef);
189   memset(buffer, 0, COUNTOF(buffer));
190   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
191   ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
192   ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
193 }
194
195 static void test_GetLocaleInfoW(void)
196 {
197   LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
198   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
199   WCHAR bufferW[80], buffer2W[80];
200   CHAR bufferA[80];
201   DWORD ret;
202   INT i;
203
204   ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
205   if (!ret) {
206       win_skip("GetLocaleInfoW() isn't implemented\n");
207       return;
208   }
209   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
210   if (!ret) {
211       win_skip("LANG_RUSSIAN locale data unavailable\n");
212       return;
213   }
214   ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
215                        bufferW, COUNTOF(bufferW));
216   if (!ret) {
217       win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
218       return;
219   }
220
221   /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
222   bufferA[0] = 'a';
223   SetLastError(0xdeadbeef);
224   ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
225                        bufferA, COUNTOF(bufferA));
226   ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
227   ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
228   ok(GetLastError() == ERROR_INVALID_FLAGS,
229      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
230
231   bufferW[0] = 'a';
232   SetLastError(0xdeadbeef);
233   ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
234                        bufferW, COUNTOF(bufferW));
235   ok(ret == 0,
236      "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
237   ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
238   ok(GetLastError() == ERROR_INVALID_FLAGS,
239      "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
240
241   /* yes, test empty 13 month entry too */
242   for (i = 0; i < 12; i++) {
243       bufferW[0] = 0;
244       ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
245                            bufferW, COUNTOF(bufferW));
246       ok(ret, "Expected non zero result\n");
247       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
248                                     ret, lstrlenW(bufferW));
249       buffer2W[0] = 0;
250       ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
251                            buffer2W, COUNTOF(buffer2W));
252       ok(ret, "Expected non zero result\n");
253       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
254                                     ret, lstrlenW(buffer2W));
255
256       ok(lstrcmpW(bufferW, buffer2W) != 0,
257            "Expected genitive name to differ, got the same for month %d\n", i+1);
258
259       /* for locale without genitive names nominative returned in both cases */
260       bufferW[0] = 0;
261       ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
262                            bufferW, COUNTOF(bufferW));
263       ok(ret, "Expected non zero result\n");
264       ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
265                                     ret, lstrlenW(bufferW));
266       buffer2W[0] = 0;
267       ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
268                            buffer2W, COUNTOF(buffer2W));
269       ok(ret, "Expected non zero result\n");
270       ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
271                                     ret, lstrlenW(buffer2W));
272
273       ok(lstrcmpW(bufferW, buffer2W) == 0,
274          "Expected same names, got different for month %d\n", i+1);
275   }
276 }
277
278 static void test_GetTimeFormatA(void)
279 {
280   int ret;
281   SYSTEMTIME  curtime;
282   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
283   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
284
285   memset(&curtime, 2, sizeof(SYSTEMTIME));
286   STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
287   SetLastError(0xdeadbeef);
288   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
289   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
290       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
291
292   curtime.wHour = 8;
293   curtime.wMinute = 56;
294   curtime.wSecond = 13;
295   curtime.wMilliseconds = 22;
296   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
297   SetLastError(0xdeadbeef);
298   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
299   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
300   EXPECT_LENA; EXPECT_EQA;
301
302   /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
303   SetLastError(0xdeadbeef);
304   ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
305   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
306      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
307
308   STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
309   SetLastError(0xdeadbeef);
310   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
311   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
312       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
313
314   STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
315   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
316   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
317   EXPECT_LENA;
318
319   STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
320   ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
321   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
322   EXPECT_LENA; EXPECT_EQA;
323
324   STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
325   ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
326   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
327   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
328       "Expected '', got '%s'\n", buffer );
329
330   STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
331   ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
332   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
333   EXPECT_LENA; EXPECT_EQA;
334
335   STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
336   strcpy(Expected, "8:56 AM");
337   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
338   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
339   EXPECT_LENA; EXPECT_EQA;
340
341   STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
342   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
343   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
344   ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
345       "Expected '8.@:56AM', got '%s'\n", buffer );
346
347   STRINGSA("s1s2s3", ""); /* Duplicate tokens */
348   ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
349   ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
350   ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
351       "Expected '', got '%s'\n", buffer );
352
353   STRINGSA("t/tt", "A/AM"); /* AM time marker */
354   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
355   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
356   EXPECT_LENA; EXPECT_EQA;
357
358   curtime.wHour = 13;
359   STRINGSA("t/tt", "P/PM"); /* PM time marker */
360   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
361   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
362   EXPECT_LENA; EXPECT_EQA;
363
364   STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
365   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
366   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
367   EXPECT_LENA; EXPECT_EQA;
368
369   STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
370   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
371   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
372   EXPECT_LENA; EXPECT_EQA;
373
374   STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
375   ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
376   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
377   EXPECT_LENA; EXPECT_EQA;
378
379   curtime.wHour = 14; /* change this to 14 or 2pm */
380   curtime.wMinute = 5;
381   curtime.wSecond = 3;
382   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 */
383   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
384   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
385   EXPECT_LENA; EXPECT_EQA;
386
387   curtime.wHour = 0;
388   STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
389   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
390   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
391   EXPECT_LENA; EXPECT_EQA;
392
393   STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
394   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
395   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
396   EXPECT_LENA; EXPECT_EQA;
397
398   /* try to convert formatting strings with more than two letters
399    * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
400    * NOTE: We expect any letter for which there is an upper case value
401    *       we should see a replacement.  For letters that DO NOT have
402    *       upper case values we should see NO REPLACEMENT.
403    */
404   curtime.wHour = 8;
405   curtime.wMinute = 56;
406   curtime.wSecond = 13;
407   curtime.wMilliseconds = 22;
408   STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
409            "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
410   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
411   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
412   EXPECT_LENA; EXPECT_EQA;
413
414   STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
415   strcpy(buffer, "text");
416   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
417   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
418   EXPECT_EQA;
419
420   STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
421            "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
422   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
423   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
424   EXPECT_LENA; EXPECT_EQA;
425
426   STRINGSA("'''", "'"); /* invalid quoted string */
427   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
428   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
429   EXPECT_LENA; EXPECT_EQA;
430
431   /* test that msdn suggested single quotation usage works as expected */
432   STRINGSA("''''", "'"); /* single quote mark */
433   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
434   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
435   EXPECT_LENA; EXPECT_EQA;
436
437   STRINGSA("''HHHHHH", "08"); /* Normal use */
438   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
439   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
440   EXPECT_LENA; EXPECT_EQA;
441
442   /* and test for normal use of the single quotation mark */
443   STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
444   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
445   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
446   EXPECT_LENA; EXPECT_EQA;
447
448   STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
449   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
450   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
451   EXPECT_LENA; EXPECT_EQA;
452
453   STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
454   ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
455   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
456   EXPECT_LENA; EXPECT_EQA;
457
458   curtime.wHour = 25;
459   STRINGSA("'123'tt", ""); /* Invalid time */
460   SetLastError(0xdeadbeef);
461   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
462   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
463       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
464
465   curtime.wHour = 12;
466   curtime.wMonth = 60; /* Invalid */
467   STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
468   ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
469   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
470   EXPECT_LENA; EXPECT_EQA;
471 }
472
473 static void test_GetDateFormatA(void)
474 {
475   int ret;
476   SYSTEMTIME  curtime;
477   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
478   LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
479   char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
480   char Broken[BUFFER_SIZE];
481   char short_day[10], month[10], genitive_month[10];
482
483   memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
484   STRINGSA("ddd',' MMM dd yy","");
485   SetLastError(0xdeadbeef);
486   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
487   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
488       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
489
490   curtime.wYear = 2002;
491   curtime.wMonth = 5;
492   curtime.wDay = 4;
493   curtime.wDayOfWeek = 3;
494   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
495   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
496   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
497   EXPECT_LENA; EXPECT_EQA;
498
499   /* Same as above but with LOCALE_NOUSEROVERRIDE */
500   STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
501   SetLastError(0xdeadbeef);
502   ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
503   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
504      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
505   EXPECT_EQA;
506
507   STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
508   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
509   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
510   EXPECT_LENA; EXPECT_EQA;
511
512   curtime.wHour = 36; /* Invalid */
513   STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
514   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
515   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
516   EXPECT_LENA; EXPECT_EQA;
517
518   STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
519   ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
520   ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
521   EXPECT_EQA;
522
523   STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
524   SetLastError(0xdeadbeef);
525   ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
526   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
527       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
528
529   STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
530   ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
531   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
532   if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
533           ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
534
535   STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
536   ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
537   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
538   EXPECT_LENA; EXPECT_EQA;
539
540   /* test for expected DATE_YEARMONTH behavior with null format */
541   /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
542   STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
543   SetLastError(0xdeadbeef);
544   ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
545   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
546      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
547   EXPECT_EQA;
548
549   /* Test that using invalid DATE_* flags results in the correct error */
550   /* and return values */
551   STRINGSA("m/d/y", ""); /* Invalid flags */
552   SetLastError(0xdeadbeef);
553   ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
554                       &curtime, input, buffer, COUNTOF(buffer));
555   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
556      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
557
558   ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
559   if (!ret)
560   {
561     win_skip("LANG_RUSSIAN locale data unavailable\n");
562     return;
563   }
564
565   /* month part should be in genitive form */
566   strcpy(genitive_month, buffer + 2);
567   ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
568   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
569   strcpy(month, buffer);
570   ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
571
572   ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
573   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
574   strcpy(short_day, buffer);
575
576   STRINGSA("dd MMMMddd dd", "");
577   sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
578   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
579   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
580   EXPECT_EQA;
581
582   STRINGSA("MMMMddd dd", "");
583   sprintf(Expected, "%s%s 04", month, short_day);
584   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
585   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
586   EXPECT_EQA;
587
588   STRINGSA("MMMMddd", "");
589   sprintf(Expected, "%s%s", month, short_day);
590   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
591   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
592   EXPECT_EQA;
593
594   STRINGSA("MMMMdd", "");
595   sprintf(Expected, "%s04", genitive_month);
596   sprintf(Broken, "%s04", month);
597   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
598   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
599   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
600      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
601      "Expected '%s', got '%s'\n", Expected, buffer);
602
603   STRINGSA("MMMMdd ddd", "");
604   sprintf(Expected, "%s04 %s", genitive_month, short_day);
605   sprintf(Broken, "%s04 %s", month, short_day);
606   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
607   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
608   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
609      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
610      "Expected '%s', got '%s'\n", Expected, buffer);
611
612   STRINGSA("dd dddMMMM", "");
613   sprintf(Expected, "04 %s%s", short_day, month);
614   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
615   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
616   EXPECT_EQA;
617
618   STRINGSA("dd dddMMMM ddd MMMMdd", "");
619   sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
620   sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
621   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
622   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
623   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
624      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
625      "Expected '%s', got '%s'\n", Expected, buffer);
626
627   /* with literal part */
628   STRINGSA("ddd',' MMMM dd", "");
629   sprintf(Expected, "%s, %s 04", short_day, genitive_month);
630   sprintf(Broken, "%s, %s 04", short_day, month);
631   ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
632   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
633   ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
634      broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
635      "Expected '%s', got '%s'\n", Expected, buffer);
636 }
637
638 static void test_GetDateFormatW(void)
639 {
640   int ret;
641   SYSTEMTIME  curtime;
642   WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
643   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
644
645   STRINGSW("",""); /* If flags is not zero then format must be NULL */
646   ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
647                        input, buffer, COUNTOF(buffer));
648   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
649   {
650     win_skip("GetDateFormatW is not implemented\n");
651     return;
652   }
653   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
654      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
655   EXPECT_EQW;
656
657   STRINGSW("",""); /* NULL buffer, len > 0 */
658   SetLastError(0xdeadbeef);
659   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
660   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
661       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
662
663   STRINGSW("",""); /* NULL buffer, len == 0 */
664   ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
665   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
666   EXPECT_LENW; EXPECT_EQW;
667
668   curtime.wYear = 2002;
669   curtime.wMonth = 10;
670   curtime.wDay = 23;
671   curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
672   curtime.wHour = 65432; /* Invalid */
673   curtime.wMinute = 34512; /* Invalid */
674   curtime.wSecond = 65535; /* Invalid */
675   curtime.wMilliseconds = 12345;
676   STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
677   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
678   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
679   EXPECT_LENW; EXPECT_EQW;
680
681   /* Limit tests */
682
683   curtime.wYear = 1601;
684   curtime.wMonth = 1;
685   curtime.wDay = 1;
686   curtime.wDayOfWeek = 0; /* Irrelevant */
687   curtime.wHour = 0;
688   curtime.wMinute = 0;
689   curtime.wSecond = 0;
690   curtime.wMilliseconds = 0;
691   STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
692   SetLastError(0xdeadbeef);
693   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
694   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
695   EXPECT_LENW; EXPECT_EQW;
696
697   curtime.wYear = 1600;
698   curtime.wMonth = 12;
699   curtime.wDay = 31;
700   curtime.wDayOfWeek = 0; /* Irrelevant */
701   curtime.wHour = 23;
702   curtime.wMinute = 59;
703   curtime.wSecond = 59;
704   curtime.wMilliseconds = 999;
705   STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
706   SetLastError(0xdeadbeef);
707   ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
708   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
709       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
710 }
711
712
713 #define CY_POS_LEFT  0
714 #define CY_POS_RIGHT 1
715 #define CY_POS_LEFT_SPACE  2
716 #define CY_POS_RIGHT_SPACE 3
717
718 static void test_GetCurrencyFormatA(void)
719 {
720   static char szDot[] = { '.', '\0' };
721   static char szComma[] = { ',', '\0' };
722   static char szDollar[] = { '$', '\0' };
723   int ret;
724   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
725   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
726   CURRENCYFMTA format;
727
728   memset(&format, 0, sizeof(format));
729
730   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
731   SetLastError(0xdeadbeef);
732   ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
733   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
734       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
735
736   STRINGSA("23,53",""); /* Invalid character --> Error */
737   SetLastError(0xdeadbeef);
738   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
739   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
740       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
741
742   STRINGSA("--",""); /* Double '-' --> Error */
743   SetLastError(0xdeadbeef);
744   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
745   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
746       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
747
748   STRINGSA("0-",""); /* Trailing '-' --> Error */
749   SetLastError(0xdeadbeef);
750   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
751   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
752       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
753
754   STRINGSA("0..",""); /* Double '.' --> Error */
755   SetLastError(0xdeadbeef);
756   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
757   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
758       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
759
760   STRINGSA(" 0.1",""); /* Leading space --> Error */
761   SetLastError(0xdeadbeef);
762   ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
763   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
764       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
765
766   STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
767   SetLastError(0xdeadbeef);
768   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
769   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
770       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
771
772   STRINGSA("2353",""); /* Format and flags given --> Error */
773   SetLastError(0xdeadbeef);
774   ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
775   ok( !ret, "Expected ret == 0, got %d\n", ret);
776   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
777       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
778
779   STRINGSA("2353",""); /* Invalid format --> Error */
780   SetLastError(0xdeadbeef);
781   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
782   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
783       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
784
785   STRINGSA("2353","$2,353.00"); /* Valid number */
786   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
787   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
788   EXPECT_LENA; EXPECT_EQA;
789
790   STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
791   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
792   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
793   EXPECT_LENA; EXPECT_EQA;
794
795   STRINGSA("2353.1","$2,353.10"); /* Valid real number */
796   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
797   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
798   EXPECT_LENA; EXPECT_EQA;
799
800   STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
801   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
802   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
803   EXPECT_LENA; EXPECT_EQA;
804
805   STRINGSA("2353.119","$2,353.12");  /* Too many DP --> Rounded */
806   ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
807   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
808   EXPECT_LENA; EXPECT_EQA;
809
810   format.NumDigits = 0; /* No decimal separator */
811   format.LeadingZero = 0;
812   format.Grouping = 0;  /* No grouping char */
813   format.NegativeOrder = 0;
814   format.PositiveOrder = CY_POS_LEFT;
815   format.lpDecimalSep = szDot;
816   format.lpThousandSep = szComma;
817   format.lpCurrencySymbol = szDollar;
818
819   STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
820   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
821   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
822   EXPECT_LENA; EXPECT_EQA;
823
824   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
825   STRINGSA("2353","$2353.0");
826   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
827   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
828   EXPECT_LENA; EXPECT_EQA;
829
830   format.Grouping = 2; /* Group by 100's */
831   STRINGSA("2353","$23,53.0");
832   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
833   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
834   EXPECT_LENA; EXPECT_EQA;
835
836   STRINGSA("235","$235.0"); /* Grouping of a positive number */
837   format.Grouping = 3;
838   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
839   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
840   EXPECT_LENA; EXPECT_EQA;
841
842   STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
843   format.NegativeOrder = 2;
844   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
845   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
846   EXPECT_LENA; EXPECT_EQA;
847
848   format.LeadingZero = 1; /* Always provide leading zero */
849   STRINGSA(".5","$0.5");
850   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
851   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
852   EXPECT_LENA; EXPECT_EQA;
853
854   format.PositiveOrder = CY_POS_RIGHT;
855   STRINGSA("1","1.0$");
856   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
857   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
858   EXPECT_LENA; EXPECT_EQA;
859
860   format.PositiveOrder = CY_POS_LEFT_SPACE;
861   STRINGSA("1","$ 1.0");
862   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
863   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
864   EXPECT_LENA; EXPECT_EQA;
865
866   format.PositiveOrder = CY_POS_RIGHT_SPACE;
867   STRINGSA("1","1.0 $");
868   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
869   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
870   EXPECT_LENA; EXPECT_EQA;
871
872   format.NegativeOrder = 0;
873   STRINGSA("-1","($1.0)");
874   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
875   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
876   EXPECT_LENA; EXPECT_EQA;
877
878   format.NegativeOrder = 1;
879   STRINGSA("-1","-$1.0");
880   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
881   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
882   EXPECT_LENA; EXPECT_EQA;
883
884   format.NegativeOrder = 2;
885   STRINGSA("-1","$-1.0");
886   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
887   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
888   EXPECT_LENA; EXPECT_EQA;
889
890   format.NegativeOrder = 3;
891   STRINGSA("-1","$1.0-");
892   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
893   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
894   EXPECT_LENA; EXPECT_EQA;
895
896   format.NegativeOrder = 4;
897   STRINGSA("-1","(1.0$)");
898   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
899   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
900   EXPECT_LENA; EXPECT_EQA;
901
902   format.NegativeOrder = 5;
903   STRINGSA("-1","-1.0$");
904   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
905   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
906   EXPECT_LENA; EXPECT_EQA;
907
908   format.NegativeOrder = 6;
909   STRINGSA("-1","1.0-$");
910   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
911   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
912   EXPECT_LENA; EXPECT_EQA;
913
914   format.NegativeOrder = 7;
915   STRINGSA("-1","1.0$-");
916   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
917   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
918   EXPECT_LENA; EXPECT_EQA;
919
920   format.NegativeOrder = 8;
921   STRINGSA("-1","-1.0 $");
922   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
923   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
924   EXPECT_LENA; EXPECT_EQA;
925
926   format.NegativeOrder = 9;
927   STRINGSA("-1","-$ 1.0");
928   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
929   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
930   EXPECT_LENA; EXPECT_EQA;
931
932   format.NegativeOrder = 10;
933   STRINGSA("-1","1.0 $-");
934   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
935   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
936   EXPECT_LENA; EXPECT_EQA;
937
938   format.NegativeOrder = 11;
939   STRINGSA("-1","$ 1.0-");
940   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
941   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942   EXPECT_LENA; EXPECT_EQA;
943
944   format.NegativeOrder = 12;
945   STRINGSA("-1","$ -1.0");
946   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
947   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
948   EXPECT_LENA; EXPECT_EQA;
949
950   format.NegativeOrder = 13;
951   STRINGSA("-1","1.0- $");
952   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
953   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
954   EXPECT_LENA; EXPECT_EQA;
955
956   format.NegativeOrder = 14;
957   STRINGSA("-1","($ 1.0)");
958   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
959   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
960   EXPECT_LENA; EXPECT_EQA;
961
962   format.NegativeOrder = 15;
963   STRINGSA("-1","(1.0 $)");
964   ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
965   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
966   EXPECT_LENA; EXPECT_EQA;
967 }
968
969 #define NEG_PARENS      0 /* "(1.1)" */
970 #define NEG_LEFT        1 /* "-1.1"  */
971 #define NEG_LEFT_SPACE  2 /* "- 1.1" */
972 #define NEG_RIGHT       3 /* "1.1-"  */
973 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
974
975 static void test_GetNumberFormatA(void)
976 {
977   static char szDot[] = { '.', '\0' };
978   static char szComma[] = { ',', '\0' };
979   int ret;
980   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
981   char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
982   NUMBERFMTA format;
983
984   memset(&format, 0, sizeof(format));
985
986   STRINGSA("23",""); /* NULL output, length > 0 --> Error */
987   SetLastError(0xdeadbeef);
988   ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
989   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
990       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
991
992   STRINGSA("23,53",""); /* Invalid character --> Error */
993   SetLastError(0xdeadbeef);
994   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
995   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
996       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
997
998   STRINGSA("--",""); /* Double '-' --> Error */
999   SetLastError(0xdeadbeef);
1000   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1001   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1002       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1003
1004   STRINGSA("0-",""); /* Trailing '-' --> Error */
1005   SetLastError(0xdeadbeef);
1006   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1007   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1008       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1009
1010   STRINGSA("0..",""); /* Double '.' --> Error */
1011   SetLastError(0xdeadbeef);
1012   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1013   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1014       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1015
1016   STRINGSA(" 0.1",""); /* Leading space --> Error */
1017   SetLastError(0xdeadbeef);
1018   ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1019   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1020       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1021
1022   STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1023   SetLastError(0xdeadbeef);
1024   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1025   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1026       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1027
1028   STRINGSA("2353",""); /* Format and flags given --> Error */
1029   SetLastError(0xdeadbeef);
1030   ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1031   ok( !ret, "Expected ret == 0, got %d\n", ret);
1032   ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1033       "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1034
1035   STRINGSA("2353",""); /* Invalid format --> Error */
1036   SetLastError(0xdeadbeef);
1037   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1038   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1039       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1040
1041   STRINGSA("2353","2,353.00"); /* Valid number */
1042   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1043   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1044   EXPECT_LENA; EXPECT_EQA;
1045
1046   STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1047   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1048   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1049   EXPECT_LENA; EXPECT_EQA;
1050
1051   STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1052   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1053   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1054   EXPECT_LENA; EXPECT_EQA;
1055
1056   STRINGSA("2353.1","2,353.10"); /* Valid real number */
1057   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1058   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1059   EXPECT_LENA; EXPECT_EQA;
1060
1061   STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1062   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1063   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064   EXPECT_LENA; EXPECT_EQA;
1065
1066   STRINGSA("2353.119","2,353.12");  /* Too many DP --> Rounded */
1067   ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1068   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1069   EXPECT_LENA; EXPECT_EQA;
1070
1071   format.NumDigits = 0; /* No decimal separator */
1072   format.LeadingZero = 0;
1073   format.Grouping = 0;  /* No grouping char */
1074   format.NegativeOrder = 0;
1075   format.lpDecimalSep = szDot;
1076   format.lpThousandSep = szComma;
1077
1078   STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1079   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1080   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1081   EXPECT_LENA; EXPECT_EQA;
1082
1083   format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1084   STRINGSA("2353","2353.0");
1085   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1086   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1087   EXPECT_LENA; EXPECT_EQA;
1088
1089   format.Grouping = 2; /* Group by 100's */
1090   STRINGSA("2353","23,53.0");
1091   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1092   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1093   EXPECT_LENA; EXPECT_EQA;
1094
1095   STRINGSA("235","235.0"); /* Grouping of a positive number */
1096   format.Grouping = 3;
1097   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1098   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1099   EXPECT_LENA; EXPECT_EQA;
1100
1101   STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1102   format.NegativeOrder = NEG_LEFT;
1103   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1104   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1105   EXPECT_LENA; EXPECT_EQA;
1106
1107   format.LeadingZero = 1; /* Always provide leading zero */
1108   STRINGSA(".5","0.5");
1109   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1110   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1111   EXPECT_LENA; EXPECT_EQA;
1112
1113   format.NegativeOrder = NEG_PARENS;
1114   STRINGSA("-1","(1.0)");
1115   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1116   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1117   EXPECT_LENA; EXPECT_EQA;
1118
1119   format.NegativeOrder = NEG_LEFT;
1120   STRINGSA("-1","-1.0");
1121   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1122   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1123   EXPECT_LENA; EXPECT_EQA;
1124
1125   format.NegativeOrder = NEG_LEFT_SPACE;
1126   STRINGSA("-1","- 1.0");
1127   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1128   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1129   EXPECT_LENA; EXPECT_EQA;
1130
1131   format.NegativeOrder = NEG_RIGHT;
1132   STRINGSA("-1","1.0-");
1133   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1134   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1135   EXPECT_LENA; EXPECT_EQA;
1136
1137   format.NegativeOrder = NEG_RIGHT_SPACE;
1138   STRINGSA("-1","1.0 -");
1139   ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1140   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1141   EXPECT_LENA; EXPECT_EQA;
1142
1143   lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1144
1145   if (IsValidLocale(lcid, 0))
1146   {
1147     STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1148     Expected[3] = 160; /* Non breaking space */
1149     ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1150     ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1151     EXPECT_LENA; EXPECT_EQA;
1152   }
1153 }
1154
1155 struct comparestringa_entry {
1156   LCID lcid;
1157   DWORD flags;
1158   const char *first;
1159   int first_len;
1160   const char *second;
1161   int second_len;
1162   int ret;
1163 };
1164
1165 static const struct comparestringa_entry comparestringa_data[] = {
1166   { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1167   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1168   { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1169   { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1170   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1171   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1172   { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1173   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1174   { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1175   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1176   { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1177   { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1178   { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1179   { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1180   { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1181   { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1182   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1183   { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1184   { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1185   /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1186   { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1187   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1188   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1189   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1190   { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1191   { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1192   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1193   { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1194   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1195   { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1196 };
1197
1198 static void test_CompareStringA(void)
1199 {
1200   int ret, i;
1201   LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1202
1203   for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1204   {
1205       const struct comparestringa_entry *entry = &comparestringa_data[i];
1206
1207       ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1208           entry->second, entry->second_len);
1209       ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1210   }
1211
1212   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1213   ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1214
1215   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1216   ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1217
1218   ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1219   ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1220
1221   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1222   ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1223
1224   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1225
1226   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1227   ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1228
1229   ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1230   ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1231
1232     ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1233     ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1234
1235     /* test for CompareStringA flags */
1236     SetLastError(0xdeadbeef);
1237     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1238     ok(GetLastError() == ERROR_INVALID_FLAGS,
1239         "unexpected error code %d\n", GetLastError());
1240     ok(!ret, "CompareStringA must fail with invalid flag\n");
1241
1242     SetLastError(0xdeadbeef);
1243     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1244     ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1245     ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1246     /* end of test for CompareStringA flags */
1247
1248     ret = lstrcmpA("", "");
1249     ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1250
1251     ret = lstrcmpA(NULL, NULL);
1252     ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1253
1254     ret = lstrcmpA("", NULL);
1255     ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1256
1257     ret = lstrcmpA(NULL, "");
1258     ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1259  
1260
1261     if (0) { /* this requires collation table patch to make it MS compatible */
1262     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1263     ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1264
1265     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1266     ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1267
1268     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1269     ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1270
1271     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1272     ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1273
1274     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1275     ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1276
1277     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1278     ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1279
1280     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1281     ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1282
1283     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1284     ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1285
1286     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1287     ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1288
1289     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1290     ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1291
1292     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1293     ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1294
1295     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1296     ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1297     }
1298
1299
1300     /* WinXP handles embedded NULLs differently than earlier versions */
1301     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1302     ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1303
1304     ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1305     ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1306
1307     ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1308     ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1309
1310     ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1311     ok(ret == CSTR_EQUAL || /* win2k */
1312        ret == CSTR_GREATER_THAN,
1313        "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1314
1315     ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1316     todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1317
1318     ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1319     todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1320
1321     ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1322     todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1323
1324     ret = lstrcmpi("#", ".");
1325     todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1326
1327     lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1328
1329     /* \xB9 character lies between a and b */
1330     ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1331     todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1332     ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1333     ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1334 }
1335
1336 static void test_LCMapStringA(void)
1337 {
1338     int ret, ret2;
1339     char buf[256], buf2[256];
1340     static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1341     static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1342     static const char symbols_stripped[] = "justateststring1";
1343
1344     SetLastError(0xdeadbeef);
1345     ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1346                        lower_case, -1, buf, sizeof(buf));
1347     ok(ret == lstrlenA(lower_case) + 1,
1348        "ret %d, error %d, expected value %d\n",
1349        ret, GetLastError(), lstrlenA(lower_case) + 1);
1350     ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1351
1352     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1353                        upper_case, -1, buf, sizeof(buf));
1354     ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1355     ok(GetLastError() == ERROR_INVALID_FLAGS,
1356        "unexpected error code %d\n", GetLastError());
1357
1358     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1359                        upper_case, -1, buf, sizeof(buf));
1360     ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1361     ok(GetLastError() == ERROR_INVALID_FLAGS,
1362        "unexpected error code %d\n", GetLastError());
1363
1364     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1365                        upper_case, -1, buf, sizeof(buf));
1366     ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1367     ok(GetLastError() == ERROR_INVALID_FLAGS,
1368        "unexpected error code %d\n", GetLastError());
1369
1370     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1371                        upper_case, -1, buf, sizeof(buf));
1372     ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1373     ok(GetLastError() == ERROR_INVALID_FLAGS,
1374        "unexpected error code %d\n", GetLastError());
1375
1376     /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1377     SetLastError(0xdeadbeef);
1378     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1379                        upper_case, -1, buf, sizeof(buf));
1380     ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1381     ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1382
1383     /* test LCMAP_LOWERCASE */
1384     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1385                        upper_case, -1, buf, sizeof(buf));
1386     ok(ret == lstrlenA(upper_case) + 1,
1387        "ret %d, error %d, expected value %d\n",
1388        ret, GetLastError(), lstrlenA(upper_case) + 1);
1389     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1390
1391     /* test LCMAP_UPPERCASE */
1392     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1393                        lower_case, -1, buf, sizeof(buf));
1394     ok(ret == lstrlenA(lower_case) + 1,
1395        "ret %d, error %d, expected value %d\n",
1396        ret, GetLastError(), lstrlenA(lower_case) + 1);
1397     ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1398
1399     /* test buffer overflow */
1400     SetLastError(0xdeadbeef);
1401     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1402                        lower_case, -1, buf, 4);
1403     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1404        "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1405
1406     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1407     lstrcpyA(buf, lower_case);
1408     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1409                        buf, -1, buf, sizeof(buf));
1410     if (!ret) /* Win9x */
1411         trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1412     else
1413     {
1414         ok(ret == lstrlenA(lower_case) + 1,
1415            "ret %d, error %d, expected value %d\n",
1416            ret, GetLastError(), lstrlenA(lower_case) + 1);
1417         ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1418     }
1419     lstrcpyA(buf, upper_case);
1420     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1421                        buf, -1, buf, sizeof(buf));
1422     if (!ret) /* Win9x */
1423         trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1424     else
1425     {
1426         ok(ret == lstrlenA(upper_case) + 1,
1427            "ret %d, error %d, expected value %d\n",
1428            ret, GetLastError(), lstrlenA(lower_case) + 1);
1429         ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1430     }
1431
1432     /* otherwise src == dst should fail */
1433     SetLastError(0xdeadbeef);
1434     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1435                        buf, 10, buf, sizeof(buf));
1436     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1437        GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1438        "unexpected error code %d\n", GetLastError());
1439     ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1440
1441     /* test whether '\0' is always appended */
1442     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1443                        upper_case, -1, buf, sizeof(buf));
1444     ok(ret, "LCMapStringA must succeed\n");
1445     ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1446     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1447                        upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1448     ok(ret2, "LCMapStringA must succeed\n");
1449     ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1450     ok(ret == ret2, "lengths of sort keys must be equal\n");
1451     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1452
1453     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1454     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1455                        upper_case, -1, buf, sizeof(buf));
1456     ok(ret, "LCMapStringA must succeed\n");
1457     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1458                        lower_case, -1, buf2, sizeof(buf2));
1459     ok(ret2, "LCMapStringA must succeed\n");
1460     ok(ret == ret2, "lengths of sort keys must be equal\n");
1461     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1462
1463     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1464        results from plain LCMAP_SORTKEY on Vista */
1465
1466     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1467     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1468                        lower_case, -1, buf, sizeof(buf));
1469     ok(ret, "LCMapStringA must succeed\n");
1470     ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1471                        symbols_stripped, -1, buf2, sizeof(buf2));
1472     ok(ret2, "LCMapStringA must succeed\n");
1473     ok(ret == ret2, "lengths of sort keys must be equal\n");
1474     ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1475
1476     /* test NORM_IGNORENONSPACE */
1477     lstrcpyA(buf, "foo");
1478     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1479                        lower_case, -1, buf, sizeof(buf));
1480     ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1481         lstrlenA(lower_case) + 1, ret);
1482     ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1483
1484     /* test NORM_IGNORESYMBOLS */
1485     lstrcpyA(buf, "foo");
1486     ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1487                        lower_case, -1, buf, sizeof(buf));
1488     ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1489         lstrlenA(symbols_stripped) + 1, ret);
1490     ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1491
1492     /* test srclen = 0 */
1493     SetLastError(0xdeadbeef);
1494     ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1495     ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1496     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1497        "unexpected error code %d\n", GetLastError());
1498 }
1499
1500 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
1501
1502 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
1503 {
1504     int ret, ret2;
1505     WCHAR buf[256], buf2[256];
1506     char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1507
1508     ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1509                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1510     if (broken(ret))
1511         ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1512     else
1513     {
1514         ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
1515         ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1516            func_name, GetLastError());
1517     }
1518
1519     ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
1520                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1521     ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
1522     ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1523        func_name, GetLastError());
1524
1525     ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1526                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1527     ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
1528     ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1529        func_name, GetLastError());
1530
1531     ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1532                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1533     ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
1534        func_name);
1535     ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
1536        func_name, GetLastError());
1537
1538     /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1539     SetLastError(0xdeadbeef);
1540     ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
1541                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1542     ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
1543        func_name, GetLastError());
1544     ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
1545
1546     /* test LCMAP_LOWERCASE */
1547     ret = func_ptr(LCMAP_LOWERCASE,
1548                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1549     ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1550        ret, GetLastError(), lstrlenW(upper_case) + 1);
1551     ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1552
1553     /* test LCMAP_UPPERCASE */
1554     ret = func_ptr(LCMAP_UPPERCASE,
1555                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1556     ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1557        ret, GetLastError(), lstrlenW(lower_case) + 1);
1558     ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1559
1560     /* test buffer overflow */
1561     SetLastError(0xdeadbeef);
1562     ret = func_ptr(LCMAP_UPPERCASE,
1563                        lower_case, -1, buf, 4);
1564     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1565        "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
1566
1567     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1568     lstrcpyW(buf, lower_case);
1569     ret = func_ptr(LCMAP_UPPERCASE,
1570                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1571     ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1572        ret, GetLastError(), lstrlenW(lower_case) + 1);
1573     ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
1574
1575     lstrcpyW(buf, upper_case);
1576     ret = func_ptr(LCMAP_LOWERCASE,
1577                        buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1578     ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
1579        ret, GetLastError(), lstrlenW(lower_case) + 1);
1580     ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
1581
1582     /* otherwise src == dst should fail */
1583     SetLastError(0xdeadbeef);
1584     ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
1585                        buf, 10, buf, sizeof(buf));
1586     ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1587        GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
1588        "%s unexpected error code %d\n", func_name, GetLastError());
1589     ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
1590
1591     /* test whether '\0' is always appended */
1592     ret = func_ptr(LCMAP_SORTKEY,
1593                        upper_case, -1, buf, sizeof(buf));
1594     ok(ret, "%s func_ptr must succeed\n", func_name);
1595     ret2 = func_ptr(LCMAP_SORTKEY,
1596                        upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1597     ok(ret, "%s func_ptr must succeed\n", func_name);
1598     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1599     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1600
1601     /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1602     ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
1603                        upper_case, -1, buf, sizeof(buf));
1604     ok(ret, "%s func_ptr must succeed\n", func_name);
1605     ret2 = func_ptr(LCMAP_SORTKEY,
1606                        lower_case, -1, buf2, sizeof(buf2));
1607     ok(ret2, "%s func_ptr must succeed\n", func_name);
1608     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1609     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1610
1611     /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1612        results from plain LCMAP_SORTKEY on Vista */
1613
1614     /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1615     ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1616                        lower_case, -1, buf, sizeof(buf));
1617     ok(ret, "%s func_ptr must succeed\n", func_name);
1618     ret2 = func_ptr(LCMAP_SORTKEY,
1619                        symbols_stripped, -1, buf2, sizeof(buf2));
1620     ok(ret2, "%s func_ptr must succeed\n", func_name);
1621     ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
1622     ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
1623
1624     /* test NORM_IGNORENONSPACE */
1625     lstrcpyW(buf, fooW);
1626     ret = func_ptr(NORM_IGNORENONSPACE,
1627                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1628     ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1629     lstrlenW(lower_case) + 1, ret);
1630     ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
1631
1632     /* test NORM_IGNORESYMBOLS */
1633     lstrcpyW(buf, fooW);
1634     ret = func_ptr(NORM_IGNORESYMBOLS,
1635                        lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1636     ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
1637     lstrlenW(symbols_stripped) + 1, ret);
1638     ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
1639
1640     /* test srclen = 0 */
1641     SetLastError(0xdeadbeef);
1642     ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1643     ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
1644     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1645        "%s unexpected error code %d\n", func_name, GetLastError());
1646 }
1647
1648 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1649 {
1650     return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
1651 }
1652
1653 static void test_LCMapStringW(void)
1654 {
1655     trace("testing LCMapStringW\n");
1656
1657     test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
1658 }
1659
1660 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
1661 {
1662     return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
1663 }
1664
1665 static void test_LCMapStringEx(void)
1666 {
1667     int ret;
1668     WCHAR buf[256];
1669
1670     if (!pLCMapStringEx)
1671     {
1672         skip( "LCMapStringEx not available\n" );
1673         return;
1674     }
1675
1676     trace("testing LCMapStringEx\n");
1677
1678     /* test reserved parameters */
1679     ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1680                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
1681     ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1682        ret, GetLastError(), lstrlenW(upper_case) + 1);
1683     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1684
1685     ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1686                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
1687     ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
1688        ret, GetLastError(), lstrlenW(upper_case) + 1);
1689     ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1690
1691     /* crashes on native */
1692     if(0)
1693         ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
1694                              upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
1695
1696     test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
1697 }
1698
1699 static void test_LocaleNames(void)
1700 {
1701     LCID lcid;
1702     INT ret;
1703     WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1704
1705     if (!pLocaleNameToLCID)
1706     {
1707         win_skip( "LocaleNameToLCID not available\n" );
1708         return;
1709     }
1710
1711     /* special cases */
1712     buffer[0] = 0;
1713     lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1714     ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1715        "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1716     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1717     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1718     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1719
1720     buffer[0] = 0;
1721     lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1722     todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1723                  "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1724     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1725     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1726     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1727
1728     buffer[0] = 0;
1729     lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1730     todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1731     ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1732     ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1733     trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1734 }
1735
1736 /* this requires collation table patch to make it MS compatible */
1737 static const char * const strings_sorted[] =
1738 {
1739 "'",
1740 "-",
1741 "!",
1742 "\"",
1743 ".",
1744 ":",
1745 "\\",
1746 "_",
1747 "`",
1748 "{",
1749 "}",
1750 "+",
1751 "0",
1752 "1",
1753 "2",
1754 "3",
1755 "4",
1756 "5",
1757 "6",
1758 "7",
1759 "8",
1760 "9",
1761 "a",
1762 "A",
1763 "b",
1764 "B",
1765 "c",
1766 "C"
1767 };
1768
1769 static const char * const strings[] =
1770 {
1771 "C",
1772 "\"",
1773 "9",
1774 "'",
1775 "}",
1776 "-",
1777 "7",
1778 "+",
1779 "`",
1780 "1",
1781 "a",
1782 "5",
1783 "\\",
1784 "8",
1785 "B",
1786 "3",
1787 "_",
1788 "6",
1789 "{",
1790 "2",
1791 "c",
1792 "4",
1793 "!",
1794 "0",
1795 "A",
1796 ":",
1797 "b",
1798 "."
1799 };
1800
1801 static int compare_string1(const void *e1, const void *e2)
1802 {
1803     const char *s1 = *(const char *const *)e1;
1804     const char *s2 = *(const char *const *)e2;
1805
1806     return lstrcmpA(s1, s2);
1807 }
1808
1809 static int compare_string2(const void *e1, const void *e2)
1810 {
1811     const char *s1 = *(const char *const *)e1;
1812     const char *s2 = *(const char *const *)e2;
1813
1814     return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1815 }
1816
1817 static int compare_string3(const void *e1, const void *e2)
1818 {
1819     const char *s1 = *(const char *const *)e1;
1820     const char *s2 = *(const char *const *)e2;
1821     char key1[256], key2[256];
1822
1823     LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1824     LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1825     return strcmp(key1, key2);
1826 }
1827
1828 static void test_sorting(void)
1829 {
1830     char buf[256];
1831     char **str_buf = (char **)buf;
1832     int i;
1833
1834     assert(sizeof(buf) >= sizeof(strings));
1835
1836     /* 1. sort using lstrcmpA */
1837     memcpy(buf, strings, sizeof(strings));
1838     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1839     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1840     {
1841         ok(!strcmp(strings_sorted[i], str_buf[i]),
1842            "qsort using lstrcmpA failed for element %d\n", i);
1843     }
1844     /* 2. sort using CompareStringA */
1845     memcpy(buf, strings, sizeof(strings));
1846     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1847     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1848     {
1849         ok(!strcmp(strings_sorted[i], str_buf[i]),
1850            "qsort using CompareStringA failed for element %d\n", i);
1851     }
1852     /* 3. sort using sort keys */
1853     memcpy(buf, strings, sizeof(strings));
1854     qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1855     for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1856     {
1857         ok(!strcmp(strings_sorted[i], str_buf[i]),
1858            "qsort using sort keys failed for element %d\n", i);
1859     }
1860 }
1861
1862 static void test_FoldStringA(void)
1863 {
1864   int ret, i, j;
1865   BOOL is_special;
1866   char src[256], dst[256];
1867   static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0'  };
1868   static const char digits_dst[] = { '1','2','3','\0'  };
1869   static const char composite_src[] =
1870   {
1871     0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1872     0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1873     0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1874     0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1875     0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1876     0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1877     0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1878     0xfb,0xfc,0xfd,0xff,'\0'
1879   };
1880   static const char composite_dst[] =
1881   {
1882     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1883     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1884     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1885     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1886     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1887     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1888     0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1889     0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1890     0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1891     0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1892     0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1893     0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1894     0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1895     0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1896     0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1897   };
1898   static const char composite_dst_alt[] =
1899   {
1900     0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1901     0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1902     0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1903     0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1904     0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1905     0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1906     0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1907     0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1908     0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1909     0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1910     0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1911     0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1912     0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1913     0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1914     0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1915   };
1916   static const char ligatures_src[] =
1917   {
1918     0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1919   };
1920   static const char ligatures_dst[] =
1921   {
1922     'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1923   };
1924   static const struct special
1925   {
1926     char src;
1927     char dst[4];
1928   }  foldczone_special[] =
1929   {
1930     /* src   dst                   */
1931     { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1932     { 0x98, { 0x20, 0x7e, 0x00 } },
1933     { 0x99, { 0x54, 0x4d, 0x00 } },
1934     { 0xa0, { 0x20, 0x00 } },
1935     { 0xa8, { 0x20, 0xa8, 0x00 } },
1936     { 0xaa, { 0x61, 0x00 } },
1937     { 0xaf, { 0x20, 0xaf, 0x00 } },
1938     { 0xb2, { 0x32, 0x00 } },
1939     { 0xb3, { 0x33, 0x00 } },
1940     { 0xb4, { 0x20, 0xb4, 0x00 } },
1941     { 0xb8, { 0x20, 0xb8, 0x00 } },
1942     { 0xb9, { 0x31, 0x00 } },
1943     { 0xba, { 0x6f, 0x00 } },
1944     { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1945     { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1946     { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1947     { 0x00 }
1948   };
1949
1950   if (!pFoldStringA)
1951     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1952
1953   /* these tests are locale specific */
1954   if (GetACP() != 1252)
1955   {
1956       trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1957       return;
1958   }
1959
1960   /* MAP_FOLDDIGITS */
1961   SetLastError(0);
1962   ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1963   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1964   {
1965     win_skip("FoldStringA is not implemented\n");
1966     return;
1967   }
1968   ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1969   ok(strcmp(dst, digits_dst) == 0,
1970      "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1971   for (i = 1; i < 256; i++)
1972   {
1973     if (!strchr(digits_src, i))
1974     {
1975       src[0] = i;
1976       src[1] = '\0';
1977       SetLastError(0);
1978       ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1979       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1980       ok(dst[0] == src[0],
1981          "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1982     }
1983   }
1984
1985   /* MAP_EXPAND_LIGATURES */
1986   SetLastError(0);
1987   ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1988   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1989   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1990     ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1991     ok(strcmp(dst, ligatures_dst) == 0,
1992        "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1993     for (i = 1; i < 256; i++)
1994     {
1995       if (!strchr(ligatures_src, i))
1996       {
1997         src[0] = i;
1998         src[1] = '\0';
1999         SetLastError(0);
2000         ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
2001         if (ret == 3)
2002         {
2003           /* Vista */
2004           ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
2005              (i == 0xFC && lstrcmpA(dst, "ue") == 0),
2006              "Got %s for %d\n", dst, i);
2007         }
2008         else
2009         {
2010           ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2011           ok(dst[0] == src[0],
2012              "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
2013         }
2014       }
2015     }
2016   }
2017
2018   /* MAP_COMPOSITE */
2019   SetLastError(0);
2020   ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
2021   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2022   ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
2023   ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
2024      "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
2025
2026   for (i = 1; i < 256; i++)
2027   {
2028     if (!strchr(composite_src, i))
2029     {
2030       src[0] = i;
2031       src[1] = '\0';
2032       SetLastError(0);
2033       ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
2034       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2035       ok(dst[0] == src[0],
2036          "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
2037          (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
2038     }
2039   }
2040
2041   /* MAP_FOLDCZONE */
2042   for (i = 1; i < 256; i++)
2043   {
2044     src[0] = i;
2045     src[1] = '\0';
2046     SetLastError(0);
2047     ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
2048     is_special = FALSE;
2049     for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
2050     {
2051       if (foldczone_special[j].src == src[0])
2052       {
2053         ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
2054            "Expected ret == 2 or %d, got %d, error %d\n",
2055            lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2056         ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2057            "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2058            (unsigned char)src[0]);
2059         is_special = TRUE;
2060       }
2061     }
2062     if (! is_special)
2063     {
2064       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2065       ok(src[0] == dst[0],
2066          "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2067          (unsigned char)src[0], (unsigned char)dst[0]);
2068     }
2069   }
2070
2071   /* MAP_PRECOMPOSED */
2072   for (i = 1; i < 256; i++)
2073   {
2074     src[0] = i;
2075     src[1] = '\0';
2076     SetLastError(0);
2077     ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2078     ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2079     ok(src[0] == dst[0],
2080        "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2081        (unsigned char)src[0], (unsigned char)dst[0]);
2082   }
2083 }
2084
2085 static void test_FoldStringW(void)
2086 {
2087   int ret;
2088   unsigned int i, j;
2089   WCHAR src[256], dst[256], ch, prev_ch = 1;
2090   static const DWORD badFlags[] =
2091   {
2092     0,
2093     MAP_PRECOMPOSED|MAP_COMPOSITE,
2094     MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2095     MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2096   };
2097   /* Ranges of digits 0-9 : Must be sorted! */
2098   static const WCHAR digitRanges[] =
2099   {
2100     0x0030, /* '0'-'9' */
2101     0x0660, /* Eastern Arabic */
2102     0x06F0, /* Arabic - Hindu */
2103     0x0966, /* Devengari */
2104     0x09E6, /* Bengalii */
2105     0x0A66, /* Gurmukhi */
2106     0x0AE6, /* Gujarati */
2107     0x0B66, /* Oriya */
2108     0x0BE6, /* Tamil - No 0 */
2109     0x0C66, /* Telugu */
2110     0x0CE6, /* Kannada */
2111     0x0D66, /* Maylayalam */
2112     0x0E50, /* Thai */
2113     0x0ED0, /* Laos */
2114     0x0F29, /* Tibet - 0 is out of sequence */
2115     0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2116     0x2080, /* Subscript */
2117     0x245F, /* Circled - 0 is out of sequence */
2118     0x2473, /* Bracketed */
2119     0x2487, /* Full stop */
2120     0x2775, /* Inverted circled - No 0 */
2121     0x277F, /* Patterned circled - No 0 */
2122     0x2789, /* Inverted Patterned circled - No 0 */
2123     0x3020, /* Hangzhou */
2124     0xff10, /* Pliene chasse (?) */
2125     0xffff  /* Terminator */
2126   };
2127   /* Digits which are represented, but out of sequence */
2128   static const WCHAR outOfSequenceDigits[] =
2129   {
2130       0xB9,   /* Superscript 1 */
2131       0xB2,   /* Superscript 2 */
2132       0xB3,   /* Superscript 3 */
2133       0x0F33, /* Tibetan half zero */
2134       0x24EA, /* Circled 0 */
2135       0x3007, /* Ideographic number zero */
2136       '\0'    /* Terminator */
2137   };
2138   /* Digits in digitRanges for which no representation is available */
2139   static const WCHAR noDigitAvailable[] =
2140   {
2141       0x0BE6, /* No Tamil 0 */
2142       0x0F29, /* No Tibetan half zero (out of sequence) */
2143       0x2473, /* No Bracketed 0 */
2144       0x2487, /* No 0 Full stop */
2145       0x2775, /* No inverted circled 0 */
2146       0x277F, /* No patterned circled */
2147       0x2789, /* No inverted Patterned circled */
2148       0x3020, /* No Hangzhou 0 */
2149       '\0'    /* Terminator */
2150   };
2151   static const WCHAR foldczone_src[] =
2152   {
2153     'W',    'i',    'n',    'e',    0x0348, 0x0551, 0x1323, 0x280d,
2154     0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2155   };
2156   static const WCHAR foldczone_dst[] =
2157   {
2158     'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2159   };
2160   static const WCHAR foldczone_todo_src[] =
2161   {
2162       0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2163   };
2164   static const WCHAR foldczone_todo_dst[] =
2165   {
2166       0x3cb,0x1f0,' ','a',0
2167   };
2168   static const WCHAR foldczone_todo_broken_dst[] =
2169   {
2170       0x3cb,0x1f0,0xa0,0xaa,0
2171   };
2172   static const WCHAR ligatures_src[] =
2173   {
2174     'W',    'i',    'n',    'e',    0x03a6, 0x03b9, 0x03bd, 0x03b5,
2175     0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2176     0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2177     0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2178     0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2179     0xfb04, 0xfb05, 0xfb06, '\0'
2180   };
2181   static const WCHAR ligatures_dst[] =
2182   {
2183     'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2184     'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2185     'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2186     'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2187     0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2188     'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2189   };
2190
2191   if (!pFoldStringW)
2192   {
2193     win_skip("FoldStringW is not available\n");
2194     return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2195   }
2196
2197   /* Invalid flag combinations */
2198   for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2199   {
2200     src[0] = dst[0] = '\0';
2201     SetLastError(0);
2202     ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2203     if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2204     {
2205       win_skip("FoldStringW is not implemented\n");
2206       return;
2207     }
2208     ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2209        "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2210   }
2211
2212   /* src & dst cannot be the same */
2213   SetLastError(0);
2214   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2215   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2216       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2217
2218   /* src can't be NULL */
2219   SetLastError(0);
2220   ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2221   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2222       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2223
2224   /* srclen can't be 0 */
2225   SetLastError(0);
2226   ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2227   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2228       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2229
2230   /* dstlen can't be < 0 */
2231   SetLastError(0);
2232   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2233   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2234       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2235
2236   /* Ret includes terminating NUL which is appended if srclen = -1 */
2237   SetLastError(0);
2238   src[0] = 'A';
2239   src[1] = '\0';
2240   dst[0] = '\0';
2241   ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2242   ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2243   ok(dst[0] == 'A' && dst[1] == '\0',
2244      "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2245      'A', '\0', ret, dst[0], dst[1], GetLastError());
2246
2247   /* If size is given, result is not NUL terminated */
2248   SetLastError(0);
2249   src[0] = 'A';
2250   src[1] = 'A';
2251   dst[0] = 'X';
2252   dst[1] = 'X';
2253   ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2254   ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2255   ok(dst[0] == 'A' && dst[1] == 'X',
2256      "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2257      'A','X', ret, dst[0], dst[1], GetLastError());
2258
2259   /* MAP_FOLDDIGITS */
2260   for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2261   {
2262     /* Check everything before this range */
2263     for (ch = prev_ch; ch < digitRanges[j]; ch++)
2264     {
2265       SetLastError(0);
2266       src[0] = ch;
2267       src[1] = dst[0] = '\0';
2268       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2269       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2270
2271       ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2272          /* Wine (correctly) maps all Unicode 4.0+ digits */
2273          isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2274          (ch >= 0x1369 && ch <= 0x1371),
2275          "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2276     }
2277
2278     if (digitRanges[j] == 0xffff)
2279       break; /* Finished the whole code point space */
2280
2281     for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2282     {
2283       WCHAR c;
2284
2285       /* Map out of sequence characters */
2286       if      (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2287       else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2288       else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2289       else if (ch == 0x245F) c = 0x24EA; /* Circled 0     */
2290       else                   c = ch;
2291       SetLastError(0);
2292       src[0] = c;
2293       src[1] = dst[0] = '\0';
2294       ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2295       ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2296
2297       ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2298          broken( dst[0] == ch ) ||  /* old Windows versions don't have all mappings */
2299          (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2300          (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2301          strchrW(noDigitAvailable, c),
2302          "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2303          ch, '0' + digitRanges[j] - ch, dst[0]);
2304     }
2305     prev_ch = ch;
2306   }
2307
2308   /* MAP_FOLDCZONE */
2309   SetLastError(0);
2310   ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2311   ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2312      "Got %d, error %d\n", ret, GetLastError());
2313   ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2314      "MAP_FOLDCZONE: Expanded incorrectly\n");
2315
2316   ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2317   todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2318           "Got %d, error %d\n", ret, GetLastError());
2319   todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2320           || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2321           "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2322
2323   /* MAP_EXPAND_LIGATURES */
2324   SetLastError(0);
2325   ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2326   /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2327   if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2328     ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2329        "Got %d, error %d\n", ret, GetLastError());
2330     ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2331        "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2332   }
2333
2334   /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2335 }
2336
2337
2338
2339 #define LCID_OK(l) \
2340   ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2341 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2342 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2343 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2344 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2345
2346 static void test_ConvertDefaultLocale(void)
2347 {
2348   LCID lcid;
2349
2350   /* Doesn't change lcid, even if non default sublang/sort used */
2351   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_US, SORT_DEFAULT);
2352   TEST_LCID(LANG_ENGLISH,  SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2353   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_DEFAULT);
2354   TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT,    SORT_JAPANESE_UNICODE);
2355
2356   /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2357   LCID_RES(MKLCID(LANG_ENGLISH,  SUBLANG_NEUTRAL, SORT_DEFAULT),
2358            MKLCID(LANG_ENGLISH,  SUBLANG_DEFAULT, SORT_DEFAULT));
2359   LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2360            MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2361
2362   /* Invariant language is not treated specially */
2363   TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2364
2365   /* User/system default languages alone are not mapped */
2366   TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2367   TEST_LCIDLANG(LANG_USER_DEFAULT,   SORT_JAPANESE_UNICODE);
2368
2369   /* Default lcids */
2370   LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2371   LCID_RES(LOCALE_USER_DEFAULT,   GetUserDefaultLCID());
2372   LCID_RES(LOCALE_NEUTRAL,        GetUserDefaultLCID());
2373 }
2374
2375 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2376                                     DWORD dwFlags, LONG_PTR lParam)
2377 {
2378   trace("%08x, %s, %s, %08x, %08lx\n",
2379         lgrpid, lpszNum, lpszName, dwFlags, lParam);
2380
2381   ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2382      "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2383
2384   /* If lParam is one, we are calling with flags defaulted from 0 */
2385   ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2386          "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2387
2388   return TRUE;
2389 }
2390
2391 static void test_EnumSystemLanguageGroupsA(void)
2392 {
2393   BOOL ret;
2394
2395   if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2396   {
2397     win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2398     return;
2399   }
2400
2401   /* No enumeration proc */
2402   SetLastError(0);
2403   ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2404   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2405   {
2406     win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2407     return;
2408   }
2409   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2410       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2411
2412   /* Invalid flags */
2413   SetLastError(0);
2414   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2415   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2416
2417   /* No flags - defaults to LGRPID_INSTALLED */
2418   SetLastError(0xdeadbeef);
2419   pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2420   ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2421
2422   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2423   pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2424 }
2425
2426 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2427 {
2428     trace( "%s %x\n", wine_dbgstr_w(name), flags );
2429     return TRUE;
2430 }
2431
2432 static void test_EnumSystemLocalesEx(void)
2433 {
2434     BOOL ret;
2435
2436     if (!pEnumSystemLocalesEx)
2437     {
2438         win_skip( "EnumSystemLocalesEx not available\n" );
2439         return;
2440     }
2441     SetLastError( 0xdeadbeef );
2442     ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2443     ok( !ret, "should have failed\n" );
2444     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2445     SetLastError( 0xdeadbeef );
2446     ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2447     ok( ret, "failed err %u\n", GetLastError() );
2448 }
2449
2450 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2451                                       LONG_PTR lParam)
2452 {
2453   trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2454
2455   /* invalid locale enumerated on some platforms */
2456   if (lcid == 0)
2457       return TRUE;
2458
2459   ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2460      "Enumerated grp %d not valid\n", lgrpid);
2461   ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2462      "Enumerated grp locale %d not valid\n", lcid);
2463   return TRUE;
2464 }
2465
2466 static void test_EnumLanguageGroupLocalesA(void)
2467 {
2468   BOOL ret;
2469
2470   if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2471   {
2472     win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2473     return;
2474   }
2475
2476   /* No enumeration proc */
2477   SetLastError(0);
2478   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2479   if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2480   {
2481     win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2482     return;
2483   }
2484   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2485       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2486
2487   /* lgrpid too small */
2488   SetLastError(0);
2489   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2490   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2491       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2492
2493   /* lgrpid too big */
2494   SetLastError(0);
2495   ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2496   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2497       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2498
2499   /* dwFlags is reserved */
2500   SetLastError(0);
2501   ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2502   ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2503       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2504
2505   pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2506 }
2507
2508 static void test_SetLocaleInfoA(void)
2509 {
2510   BOOL bRet;
2511   LCID lcid = GetUserDefaultLCID();
2512
2513   /* Null data */
2514   SetLastError(0);
2515   bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2516   ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2517       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2518
2519   /* IDATE */
2520   SetLastError(0);
2521   bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2522   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2523      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2524
2525   /* ILDATE */
2526   SetLastError(0);
2527   bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2528   ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2529      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2530 }
2531
2532 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2533 {
2534   trace("%s %08lx\n", value, lParam);
2535   return(TRUE);
2536 }
2537
2538 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2539 {
2540   ok(!enumCount, "callback called again unexpected\n");
2541   enumCount++;
2542   return(FALSE);
2543 }
2544
2545 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2546 {
2547   ok(0,"callback called unexpected\n");
2548   return(FALSE);
2549 }
2550
2551 static void test_EnumUILanguageA(void)
2552 {
2553   BOOL ret;
2554   if (!pEnumUILanguagesA) {
2555     win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2556     return;
2557   }
2558
2559   SetLastError(ERROR_SUCCESS);
2560   ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2561   if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2562   {
2563     win_skip("EnumUILanguagesA is not implemented\n");
2564     return;
2565   }
2566   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2567
2568   enumCount = 0;
2569   SetLastError(ERROR_SUCCESS);
2570   ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2571   ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2572
2573   SetLastError(ERROR_SUCCESS);
2574   ret = pEnumUILanguagesA(NULL, 0, 0);
2575   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2576   ok(GetLastError() == ERROR_INVALID_PARAMETER,
2577       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2578
2579   SetLastError(ERROR_SUCCESS);
2580   ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2581   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2582   ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2583
2584   SetLastError(ERROR_SUCCESS);
2585   ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2586   ok(!ret, "Expected return value FALSE, got %u\n", ret);
2587   ok(GetLastError() == ERROR_INVALID_PARAMETER,
2588       "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2589 }
2590
2591 static char date_fmt_buf[1024];
2592
2593 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2594 {
2595     lstrcatA(date_fmt_buf, fmt);
2596     lstrcatA(date_fmt_buf, "\n");
2597     return TRUE;
2598 }
2599
2600 static void test_EnumDateFormatsA(void)
2601 {
2602     char *p, buf[256];
2603     BOOL ret;
2604     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2605
2606     trace("EnumDateFormatsA 0\n");
2607     date_fmt_buf[0] = 0;
2608     SetLastError(0xdeadbeef);
2609     ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2610     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2611     {
2612         win_skip("0 for dwFlags is not supported\n");
2613     }
2614     else
2615     {
2616         ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2617         trace("%s\n", date_fmt_buf);
2618         /* test the 1st enumerated format */
2619         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2620         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2621         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2622         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2623     }
2624
2625     trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2626     date_fmt_buf[0] = 0;
2627     SetLastError(0xdeadbeef);
2628     ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2629     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2630     {
2631         win_skip("LOCALE_USE_CP_ACP is not supported\n");
2632     }
2633     else
2634     {
2635         ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2636         trace("%s\n", date_fmt_buf);
2637         /* test the 1st enumerated format */
2638         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2639         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2640         ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2641         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2642     }
2643
2644     trace("EnumDateFormatsA DATE_SHORTDATE\n");
2645     date_fmt_buf[0] = 0;
2646     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2647     ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2648     trace("%s\n", date_fmt_buf);
2649     /* test the 1st enumerated format */
2650     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2651     ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2652     ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2653     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2654
2655     trace("EnumDateFormatsA DATE_LONGDATE\n");
2656     date_fmt_buf[0] = 0;
2657     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2658     ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2659     trace("%s\n", date_fmt_buf);
2660     /* test the 1st enumerated format */
2661     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2662     ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2663     ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2664     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2665
2666     trace("EnumDateFormatsA DATE_YEARMONTH\n");
2667     date_fmt_buf[0] = 0;
2668     SetLastError(0xdeadbeef);
2669     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2670     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2671     {
2672         skip("DATE_YEARMONTH is only present on W2K and later\n");
2673         return;
2674     }
2675     ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2676     trace("%s\n", date_fmt_buf);
2677     /* test the 1st enumerated format */
2678     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2679     ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2680     ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2681     ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2682        "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2683 }
2684
2685 static void test_EnumTimeFormatsA(void)
2686 {
2687     char *p, buf[256];
2688     BOOL ret;
2689     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2690
2691     trace("EnumTimeFormatsA 0\n");
2692     date_fmt_buf[0] = 0;
2693     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2694     ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2695     trace("%s\n", date_fmt_buf);
2696     /* test the 1st enumerated format */
2697     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2698     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2699     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2700     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2701
2702     trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2703     date_fmt_buf[0] = 0;
2704     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2705     ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2706     trace("%s\n", date_fmt_buf);
2707     /* test the 1st enumerated format */
2708     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2709     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2710     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2711     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2712 }
2713
2714 static void test_GetCPInfo(void)
2715 {
2716     BOOL ret;
2717     CPINFO cpinfo;
2718
2719     SetLastError(0xdeadbeef);
2720     ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2721     ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2722     ok(GetLastError() == ERROR_INVALID_PARAMETER,
2723        "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2724
2725     SetLastError(0xdeadbeef);
2726     ret = GetCPInfo(CP_UTF7, &cpinfo);
2727     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2728     {
2729         skip("Codepage CP_UTF7 is not installed/available\n");
2730     }
2731     else
2732     {
2733         ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2734         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2735         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2736         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2737         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2738         ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2739     }
2740
2741     SetLastError(0xdeadbeef);
2742     ret = GetCPInfo(CP_UTF8, &cpinfo);
2743     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2744     {
2745         skip("Codepage CP_UTF8 is not installed/available\n");
2746     }
2747     else
2748     {
2749         ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2750         ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2751         ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2752         ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2753         ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2754         ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2755            "expected 4, got %u\n", cpinfo.MaxCharSize);
2756     }
2757 }
2758
2759 /*
2760  * The CT_TYPE1 has varied over windows version.
2761  * The current target for correct behavior is windows 7.
2762  * There was a big shift between windows 2000 (first introduced) and windows Xp
2763  * Most of the old values below are from windows 2000.
2764  * A smaller subset of changes happened between windows Xp and Window vista/7
2765  */
2766 static void test_GetStringTypeW(void)
2767 {
2768     static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2769     static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2770                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2771                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2772                                  C1_SPACE | C1_BLANK | C1_DEFINED,
2773                                  C1_CNTRL | C1_BLANK | C1_DEFINED};
2774     static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2775                                     C1_SPACE | C1_BLANK,
2776                                     C1_SPACE | C1_BLANK,
2777                                     C1_SPACE | C1_BLANK,
2778                                     C1_SPACE | C1_BLANK};
2779
2780     static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2781
2782                                   /* Lu, Ll, Lt */
2783     static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2784     static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2785                                      C1_LOWER | C1_ALPHA,
2786                                      C1_UPPER | C1_LOWER | C1_ALPHA,
2787                                      C1_ALPHA};
2788
2789                                   /* Sk, Sk, Mn, So, Me */
2790     static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2791                                  /* Sc, Sm, No,*/
2792                                      0xffe0, 0xffe9, 0x2153};
2793
2794                                 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2795     static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2796     static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2797     static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2798                                       C1_ALPHA | C1_DEFINED,
2799                                       C1_CNTRL | C1_DEFINED,
2800                                       C1_PUNCT | C1_DEFINED,
2801                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2802                                       C1_ALPHA | C1_LOWER | C1_DEFINED,
2803                                       C1_ALPHA | C1_DEFINED };
2804     static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2805                                       C1_ALPHA | C1_DEFINED,
2806                                       C1_CNTRL | C1_DEFINED,
2807                                       C1_PUNCT | C1_CNTRL | C1_DEFINED,
2808                                       C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2809                                       C1_ALPHA | C1_DEFINED,
2810                                       C1_DEFINED
2811  };
2812                                 /* Pc,  Pd, Ps, Pe, Pi, Pf, Po*/
2813     static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2814
2815     static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2816                                           0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2817     static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2818     static const WCHAR lower_special[] = {0x2071, 0x207f};
2819     static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2820                   0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2821                   0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2822                   0xfff9, 0xfffa, 0xfffb};
2823     static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2824
2825     WORD types[20];
2826     int i;
2827
2828     memset(types,0,sizeof(types));
2829     GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2830     for (i = 0; i < 5; i++)
2831         ok(types[i] == blanks_new[i] || broken(types[i] == blanks_old[i] || broken(types[i] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks[i],types[i],blanks_new[i]);
2832
2833     memset(types,0,sizeof(types));
2834     GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2835     for (i = 0; i < 3; i++)
2836         ok(types[i] == (C1_DEFINED | alpha_old[i]) || broken(types[i] == alpha_old[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha[i], types[i],(C1_DEFINED | alpha_old[i]));
2837     memset(types,0,sizeof(types));
2838     GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2839     for (i = 0; i < 5; i++)
2840         ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2841
2842     memset(types,0,sizeof(types));
2843     GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2844     for (i = 0; i < 8; i++)
2845         ok(types[i] == C1_DEFINED || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc[i], types[i], C1_DEFINED);
2846
2847     memset(types,0,sizeof(types));
2848     GetStringTypeW(CT_CTYPE1, changed, 7, types);
2849     for (i = 0; i < 7; i++)
2850         ok(types[i] == changed_new[i] || broken(types[i] == changed_old[i]) || broken(types[i] == changed_xp[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed[i], types[i], changed_new[i]);
2851
2852     memset(types,0,sizeof(types));
2853     GetStringTypeW(CT_CTYPE1, punct, 7, types);
2854     for (i = 0; i < 7; i++)
2855         ok(types[i] == (C1_PUNCT | C1_DEFINED) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct[i], types[i], (C1_PUNCT | C1_DEFINED));
2856
2857
2858     memset(types,0,sizeof(types));
2859     GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
2860     for (i = 0; i < 12; i++)
2861         ok(types[i]  & C1_PUNCT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special[i], types[i], C1_PUNCT);
2862
2863     memset(types,0,sizeof(types));
2864     GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
2865     for (i = 0; i < 3; i++)
2866         ok(types[i] & C1_DIGIT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special[i], types[i], C1_DIGIT);
2867
2868     memset(types,0,sizeof(types));
2869     GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
2870     for (i = 0; i < 2; i++)
2871         ok(types[i] & C1_LOWER || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special[i], types[i], C1_LOWER);
2872
2873     memset(types,0,sizeof(types));
2874     GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
2875     for (i = 0; i < 20; i++)
2876         ok(types[i] & C1_CNTRL || broken(types[i] == (C1_BLANK|C1_SPACE)) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special[i], types[i], C1_CNTRL);
2877
2878     memset(types,0,sizeof(types));
2879     GetStringTypeW(CT_CTYPE1, space_special, 3, types);
2880     for (i = 0; i < 3; i++)
2881         ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
2882 }
2883
2884 static void test_IdnToNameprepUnicode(void)
2885 {
2886     struct {
2887         DWORD in_len;
2888         const WCHAR in[64];
2889         DWORD ret;
2890         const WCHAR out[64];
2891         DWORD flags;
2892         DWORD err;
2893         DWORD todo;
2894     } test_data[] = {
2895         {
2896             5, {'t','e','s','t',0},
2897             5, {'t','e','s','t',0},
2898             0, 0xdeadbeef
2899         },
2900         {
2901             3, {'a',0xe111,'b'},
2902             0, {0},
2903             0, ERROR_INVALID_NAME
2904         },
2905         {
2906             4, {'t',0,'e',0},
2907             0, {0},
2908             0, ERROR_INVALID_NAME
2909         },
2910         {
2911             1, {'T',0},
2912             1, {'T',0},
2913             0, 0xdeadbeef
2914         },
2915         {
2916             1, {0},
2917             0, {0},
2918             0, ERROR_INVALID_NAME
2919         },
2920         {
2921             6, {' ','-','/','[',']',0},
2922             6, {' ','-','/','[',']',0},
2923             0, 0xdeadbeef
2924         },
2925         {
2926             3, {'a','-','a'},
2927             3, {'a','-','a'},
2928             IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
2929         },
2930         {
2931             3, {'a','a','-'},
2932             0, {0},
2933             IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
2934         },
2935         { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
2936             10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
2937             12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
2938             0, 0xdeadbeef, TRUE
2939         },
2940         {
2941             11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
2942             2, {'t',0},
2943             0, 0xdeadbeef
2944         },
2945         { /* Another example of incorrectly working FoldString (composition) */
2946             2, {0x3b0, 0},
2947             2, {0x3b0, 0},
2948             0, 0xdeadbeef, TRUE
2949         },
2950         {
2951             2, {0x221, 0},
2952             0, {0},
2953             0, ERROR_NO_UNICODE_TRANSLATION
2954         },
2955         {
2956             2, {0x221, 0},
2957             2, {0x221, 0},
2958             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
2959         },
2960         {
2961             5, {'a','.','.','a',0},
2962             0, {0},
2963             0, ERROR_INVALID_NAME
2964         },
2965         {
2966             3, {'a','.',0},
2967             3, {'a','.',0},
2968             0, 0xdeadbeef
2969         },
2970     };
2971
2972     WCHAR buf[1024];
2973     DWORD i, ret, err;
2974
2975     if (!pIdnToNameprepUnicode)
2976     {
2977         win_skip("IdnToNameprepUnicode is not available\n");
2978         return;
2979     }
2980
2981     ret = pIdnToNameprepUnicode(0, test_data[0].in,
2982             test_data[0].in_len, NULL, 0);
2983     ok(ret == test_data[0].ret, "ret = %d\n", ret);
2984
2985     SetLastError(0xdeadbeef);
2986     ret = pIdnToNameprepUnicode(0, test_data[1].in,
2987             test_data[1].in_len, NULL, 0);
2988     err = GetLastError();
2989     ok(ret == test_data[1].ret, "ret = %d\n", ret);
2990     ok(err == test_data[1].err, "err = %d\n", err);
2991
2992     SetLastError(0xdeadbeef);
2993     ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
2994             buf, sizeof(buf)/sizeof(WCHAR));
2995     err = GetLastError();
2996     ok(ret == test_data[0].ret, "ret = %d\n", ret);
2997     ok(err == 0xdeadbeef, "err = %d\n", err);
2998
2999     SetLastError(0xdeadbeef);
3000     ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
3001             buf, sizeof(buf)/sizeof(WCHAR));
3002     err = GetLastError();
3003     ok(ret == 0, "ret = %d\n", ret);
3004     ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3005
3006     SetLastError(0xdeadbeef);
3007     ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
3008             buf, sizeof(buf)/sizeof(WCHAR));
3009     err = GetLastError();
3010     ok(ret == 0, "ret = %d\n", ret);
3011     ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
3012
3013     ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
3014             test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
3015     ok(ret == test_data[0].ret, "ret = %d\n", ret);
3016
3017     SetLastError(0xdeadbeef);
3018     ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
3019     err = GetLastError();
3020     ok(ret == 0, "ret = %d\n", ret);
3021     ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
3022
3023     SetLastError(0xdeadbeef);
3024     ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
3025     err = GetLastError();
3026     ok(ret == 0, "ret = %d\n", ret);
3027     ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
3028
3029     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3030     {
3031         SetLastError(0xdeadbeef);
3032         ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
3033                 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
3034         err = GetLastError();
3035         if(!test_data[i].todo) {
3036             ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3037             ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3038             ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3039                     "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3040         }else {
3041             todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3042                     "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3043         }
3044     }
3045 }
3046
3047 static void test_IdnToAscii(void)
3048 {
3049     struct {
3050         DWORD in_len;
3051         const WCHAR in[64];
3052         DWORD ret;
3053         const WCHAR out[64];
3054         DWORD flags;
3055         DWORD err;
3056     } test_data[] = {
3057         {
3058             5, {'T','e','s','t',0},
3059             5, {'T','e','s','t',0},
3060             0, 0xdeadbeef
3061         },
3062         {
3063             5, {'T','e',0x017c,'s','t',0},
3064             12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
3065             0, 0xdeadbeef
3066         },
3067         {
3068             12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
3069             26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
3070             0, 0xdeadbeef
3071         },
3072         {
3073             3, {0x0105,'.',0},
3074             9, {'x','n','-','-','2','d','a','.',0},
3075             0, 0xdeadbeef
3076         },
3077         {
3078             10, {'h','t','t','p',':','/','/','t',0x0106,0},
3079             17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
3080             0, 0xdeadbeef
3081         },
3082         {
3083             10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
3084             35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
3085                 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
3086             0, 0xdeadbeef
3087         },
3088         {
3089             2, {0x221,0},
3090             8, {'x','n','-','-','6','l','a',0},
3091             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3092         },
3093     };
3094
3095     WCHAR buf[1024];
3096     DWORD i, ret, err;
3097
3098     if (!pIdnToAscii)
3099     {
3100         win_skip("IdnToAscii is not available\n");
3101         return;
3102     }
3103
3104     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3105     {
3106         SetLastError(0xdeadbeef);
3107         ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
3108                 test_data[i].in_len, buf, sizeof(buf));
3109         err = GetLastError();
3110         ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3111         ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3112         ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3113                 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3114     }
3115 }
3116
3117 static void test_IdnToUnicode(void)
3118 {
3119     struct {
3120         DWORD in_len;
3121         const WCHAR in[64];
3122         DWORD ret;
3123         const WCHAR out[64];
3124         DWORD flags;
3125         DWORD err;
3126     } test_data[] = {
3127         {
3128             5, {'T','e','s','.',0},
3129             5, {'T','e','s','.',0},
3130             0, 0xdeadbeef
3131         },
3132         {
3133             2, {0x105,0},
3134             0, {0},
3135             0, ERROR_INVALID_NAME
3136         },
3137         {
3138             33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
3139                 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
3140             23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
3141                 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
3142                 0x05d1,0x05e8,0x05d9,0x05ea,0},
3143             0, 0xdeadbeef
3144         },
3145         {
3146             34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
3147                 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
3148             16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
3149                 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
3150             0, 0xdeadbeef
3151         },
3152         {
3153             64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3154                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3155                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
3156                 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
3157             0, {0},
3158             0, ERROR_INVALID_NAME
3159         },
3160         {
3161             8, {'x','n','-','-','6','l','a',0},
3162             2, {0x221,0},
3163             IDN_ALLOW_UNASSIGNED, 0xdeadbeef
3164         },
3165     };
3166
3167     WCHAR buf[1024];
3168     DWORD i, ret, err;
3169
3170     if (!pIdnToUnicode)
3171     {
3172         win_skip("IdnToUnicode is not available\n");
3173         return;
3174     }
3175
3176     for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
3177     {
3178         SetLastError(0xdeadbeef);
3179         ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
3180                 test_data[i].in_len, buf, sizeof(buf));
3181         err = GetLastError();
3182         ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
3183         ok(err == test_data[i].err, "%d) err = %d\n", i, err);
3184         ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
3185                 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
3186     }
3187 }
3188
3189 START_TEST(locale)
3190 {
3191   InitFunctionPointers();
3192
3193   test_EnumTimeFormatsA();
3194   test_EnumDateFormatsA();
3195   test_GetLocaleInfoA();
3196   test_GetLocaleInfoW();
3197   test_GetTimeFormatA();
3198   test_GetDateFormatA();
3199   test_GetDateFormatW();
3200   test_GetCurrencyFormatA(); /* Also tests the W version */
3201   test_GetNumberFormatA();   /* Also tests the W version */
3202   test_CompareStringA();
3203   test_LCMapStringA();
3204   test_LCMapStringW();
3205   test_LCMapStringEx();
3206   test_LocaleNames();
3207   test_FoldStringA();
3208   test_FoldStringW();
3209   test_ConvertDefaultLocale();
3210   test_EnumSystemLanguageGroupsA();
3211   test_EnumSystemLocalesEx();
3212   test_EnumLanguageGroupLocalesA();
3213   test_SetLocaleInfoA();
3214   test_EnumUILanguageA();
3215   test_GetCPInfo();
3216   test_GetStringTypeW();
3217   test_IdnToNameprepUnicode();
3218   test_IdnToAscii();
3219   test_IdnToUnicode();
3220   /* this requires collation table patch to make it MS compatible */
3221   if (0) test_sorting();
3222 }