sync kernel32 winetest with wine 1.1.33
[reactos.git] / rostests / winetests / kernel32 / 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
32 #include "wine/test.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winnls.h"
37
38 static inline unsigned int strlenW( const WCHAR *str )
39 {
40 const WCHAR *s = str;
41 while (*s) s++;
42 return s - str;
43 }
44
45 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
46 {
47 if (n <= 0) return 0;
48 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
49 return *str1 - *str2;
50 }
51
52 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
53 {
54 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
55 return NULL;
56 }
57
58 static inline int isdigitW( WCHAR wc )
59 {
60 WORD type;
61 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
62 return type & C1_DIGIT;
63 }
64
65 /* Some functions are only in later versions of kernel32.dll */
66 static HMODULE hKernel32;
67 static WORD enumCount;
68
69 typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
70 DWORD, LONG_PTR);
71 static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
72 typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
73 LGRPID, DWORD, LONG_PTR);
74 static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
75 typedef BOOL (WINAPI *EnumUILanguagesAFn)(UILANGUAGE_ENUMPROC,
76 DWORD, LONG_PTR);
77 static EnumUILanguagesAFn pEnumUILanguagesA;
78
79 typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
80 static FoldStringAFn pFoldStringA;
81 typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
82 static FoldStringWFn pFoldStringW;
83
84 typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
85 static IsValidLanguageGroupFn pIsValidLanguageGroup;
86
87 static void InitFunctionPointers(void)
88 {
89 hKernel32 = GetModuleHandleA("kernel32");
90 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
91 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
92 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
93 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
94 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
95 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
96 }
97
98 #define eq(received, expected, label, type) \
99 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
100 (label), (received), (expected))
101
102 #define BUFFER_SIZE 128
103 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
104
105 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
106 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
107 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
108 "Expected '%s', got '%s'\n", Expected, buffer)
109
110 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
111 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
112 SetLastError(0xdeadbeef); buffer[0] = '\0'
113 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
114 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
115
116 #define NUO LOCALE_NOUSEROVERRIDE
117
118 static void test_GetLocaleInfoA(void)
119 {
120 int ret;
121 int len;
122 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
123 char buffer[BUFFER_SIZE];
124 char expected[BUFFER_SIZE];
125
126 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
127
128 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
129 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
130 assumes SUBLANG_NEUTRAL for zh */
131 memset(expected, 0, COUNTOF(expected));
132 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
133 SetLastError(0xdeadbeef);
134 memset(buffer, 0, COUNTOF(buffer));
135 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
136 ok((ret == len) && !lstrcmpA(buffer, expected),
137 "got %d with '%s' (expected %d with '%s')\n",
138 ret, buffer, len, expected);
139
140 memset(expected, 0, COUNTOF(expected));
141 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
142 if (len) {
143 SetLastError(0xdeadbeef);
144 memset(buffer, 0, COUNTOF(buffer));
145 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
146 ok((ret == len) && !lstrcmpA(buffer, expected),
147 "got %d with '%s' (expected %d with '%s')\n",
148 ret, buffer, len, expected);
149 }
150 else
151 win_skip("LANG_ARABIC not installed\n");
152
153 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
154 memset(expected, 0, COUNTOF(expected));
155 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
156 SetLastError(0xdeadbeef);
157 memset(buffer, 0, COUNTOF(buffer));
158 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
159 ok((ret == len) && !lstrcmpA(buffer, expected),
160 "got %d with '%s' (expected %d with '%s')\n",
161 ret, buffer, len, expected);
162
163
164 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
165 * partially fill the buffer even if it is too short. See bug 637.
166 */
167 SetLastError(0xdeadbeef);
168 memset(buffer, 0, COUNTOF(buffer));
169 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
170 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
171
172 SetLastError(0xdeadbeef);
173 memset(buffer, 0, COUNTOF(buffer));
174 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
175 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
176 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
177 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
178
179 SetLastError(0xdeadbeef);
180 memset(buffer, 0, COUNTOF(buffer));
181 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
182 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
183 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
184 }
185
186 static void test_GetLocaleInfoW(void)
187 {
188 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
189 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
190 WCHAR bufferW[80], buffer2W[80];
191 CHAR bufferA[80];
192 DWORD ret;
193 INT i;
194
195 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
196 if (!ret) {
197 win_skip("GetLocaleInfoW() isn't implemented\n");
198 return;
199 }
200 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
201 if (!ret) {
202 win_skip("LANG_RUSSIAN locale data unavailable\n");
203 return;
204 }
205 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
206 bufferW, COUNTOF(bufferW));
207 if (!ret) {
208 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
209 return;
210 }
211
212 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
213 bufferA[0] = 'a';
214 SetLastError(0xdeadbeef);
215 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
216 bufferA, COUNTOF(bufferA));
217 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
218 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
219 ok(GetLastError() == ERROR_INVALID_FLAGS,
220 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
221
222 bufferW[0] = 'a';
223 SetLastError(0xdeadbeef);
224 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
225 bufferW, COUNTOF(bufferW));
226 ok(ret == 0,
227 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
228 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
229 ok(GetLastError() == ERROR_INVALID_FLAGS,
230 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
231
232 /* yes, test empty 13 month entry too */
233 for (i = 0; i < 12; i++) {
234 bufferW[0] = 0;
235 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
236 bufferW, COUNTOF(bufferW));
237 ok(ret, "Expected non zero result\n");
238 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
239 ret, lstrlenW(bufferW));
240 buffer2W[0] = 0;
241 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
242 buffer2W, COUNTOF(buffer2W));
243 ok(ret, "Expected non zero result\n");
244 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
245 ret, lstrlenW(buffer2W));
246
247 ok(lstrcmpW(bufferW, buffer2W) != 0,
248 "Expected genitive name to differ, got the same for month %d\n", i+1);
249
250 /* for locale without genitive names nominative returned in both cases */
251 bufferW[0] = 0;
252 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
253 bufferW, COUNTOF(bufferW));
254 ok(ret, "Expected non zero result\n");
255 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
256 ret, lstrlenW(bufferW));
257 buffer2W[0] = 0;
258 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
259 buffer2W, COUNTOF(buffer2W));
260 ok(ret, "Expected non zero result\n");
261 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
262 ret, lstrlenW(buffer2W));
263
264 ok(lstrcmpW(bufferW, buffer2W) == 0,
265 "Expected same names, got different for month %d\n", i+1);
266 }
267 }
268
269 static void test_GetTimeFormatA(void)
270 {
271 int ret;
272 SYSTEMTIME curtime;
273 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
274 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
275
276 memset(&curtime, 2, sizeof(SYSTEMTIME));
277 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
278 SetLastError(0xdeadbeef);
279 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
280 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
281 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
282
283 curtime.wHour = 8;
284 curtime.wMinute = 56;
285 curtime.wSecond = 13;
286 curtime.wMilliseconds = 22;
287 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
288 SetLastError(0xdeadbeef);
289 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
290 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
291 EXPECT_LENA; EXPECT_EQA;
292
293 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
294 SetLastError(0xdeadbeef);
295 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
296 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
297 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
298
299 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
300 SetLastError(0xdeadbeef);
301 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
302 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
303 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
304
305 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
306 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
307 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
308 EXPECT_LENA;
309
310 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
311 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
312 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
313 EXPECT_LENA; EXPECT_EQA;
314
315 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
316 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
317 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
318 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
319 "Expected '', got '%s'\n", buffer );
320
321 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
322 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
323 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
324 EXPECT_LENA; EXPECT_EQA;
325
326 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
327 strcpy(Expected, "8:56 AM");
328 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
329 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
330 EXPECT_LENA; EXPECT_EQA;
331
332 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
333 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
334 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
335 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
336 "Expected '8.@:56AM', got '%s'\n", buffer );
337
338 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
339 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
340 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
341 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
342 "Expected '', got '%s'\n", buffer );
343
344 STRINGSA("t/tt", "A/AM"); /* AM time marker */
345 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
346 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
347 EXPECT_LENA; EXPECT_EQA;
348
349 curtime.wHour = 13;
350 STRINGSA("t/tt", "P/PM"); /* PM time marker */
351 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
352 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
353 EXPECT_LENA; EXPECT_EQA;
354
355 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
356 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
357 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
358 EXPECT_LENA; EXPECT_EQA;
359
360 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
361 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
362 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
363 EXPECT_LENA; EXPECT_EQA;
364
365 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
366 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
368 EXPECT_LENA; EXPECT_EQA;
369
370 curtime.wHour = 14; /* change this to 14 or 2pm */
371 curtime.wMinute = 5;
372 curtime.wSecond = 3;
373 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 */
374 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
375 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
376 EXPECT_LENA; EXPECT_EQA;
377
378 curtime.wHour = 0;
379 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
380 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
381 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
382 EXPECT_LENA; EXPECT_EQA;
383
384 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
385 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
386 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
387 EXPECT_LENA; EXPECT_EQA;
388
389 /* try to convert formatting strings with more than two letters
390 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
391 * NOTE: We expect any letter for which there is an upper case value
392 * we should see a replacement. For letters that DO NOT have
393 * upper case values we should see NO REPLACEMENT.
394 */
395 curtime.wHour = 8;
396 curtime.wMinute = 56;
397 curtime.wSecond = 13;
398 curtime.wMilliseconds = 22;
399 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
400 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
401 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
402 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
403 EXPECT_LENA; EXPECT_EQA;
404
405 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
406 strcpy(buffer, "text");
407 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
408 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
409 EXPECT_EQA;
410
411 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
412 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
413 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
414 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
415 EXPECT_LENA; EXPECT_EQA;
416
417 STRINGSA("'''", "'"); /* invalid quoted string */
418 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
419 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
420 EXPECT_LENA; EXPECT_EQA;
421
422 /* test that msdn suggested single quotation usage works as expected */
423 STRINGSA("''''", "'"); /* single quote mark */
424 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
425 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
426 EXPECT_LENA; EXPECT_EQA;
427
428 STRINGSA("''HHHHHH", "08"); /* Normal use */
429 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
430 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
431 EXPECT_LENA; EXPECT_EQA;
432
433 /* and test for normal use of the single quotation mark */
434 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
435 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
436 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
437 EXPECT_LENA; EXPECT_EQA;
438
439 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
440 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
441 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
442 EXPECT_LENA; EXPECT_EQA;
443
444 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
445 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
446 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
447 EXPECT_LENA; EXPECT_EQA;
448
449 curtime.wHour = 25;
450 STRINGSA("'123'tt", ""); /* Invalid time */
451 SetLastError(0xdeadbeef);
452 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
453 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
454 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
455
456 curtime.wHour = 12;
457 curtime.wMonth = 60; /* Invalid */
458 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
459 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
460 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
461 EXPECT_LENA; EXPECT_EQA;
462 }
463
464 static void test_GetDateFormatA(void)
465 {
466 int ret;
467 SYSTEMTIME curtime;
468 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
469 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
470
471 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
472 STRINGSA("ddd',' MMM dd yy","");
473 SetLastError(0xdeadbeef);
474 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
475 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
476 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
477
478 curtime.wYear = 2002;
479 curtime.wMonth = 5;
480 curtime.wDay = 4;
481 curtime.wDayOfWeek = 3;
482 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
483 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
484 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
485 EXPECT_LENA; EXPECT_EQA;
486
487 /* Same as above but with LOCALE_NOUSEROVERRIDE */
488 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
489 SetLastError(0xdeadbeef);
490 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
491 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
492 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
493 EXPECT_EQA;
494
495 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
496 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
498 EXPECT_LENA; EXPECT_EQA;
499
500 curtime.wHour = 36; /* Invalid */
501 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
502 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
503 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
504 EXPECT_LENA; EXPECT_EQA;
505
506 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
507 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
508 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
509 EXPECT_EQA;
510
511 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
512 SetLastError(0xdeadbeef);
513 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
514 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
515 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
516
517 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
518 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
519 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
520 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
521 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
522
523 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
524 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
525 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
526 EXPECT_LENA; EXPECT_EQA;
527
528 /* test for expected DATE_YEARMONTH behavior with null format */
529 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
530 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
531 SetLastError(0xdeadbeef);
532 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
533 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
534 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
535 EXPECT_EQA;
536
537 /* Test that using invalid DATE_* flags results in the correct error */
538 /* and return values */
539 STRINGSA("m/d/y", ""); /* Invalid flags */
540 SetLastError(0xdeadbeef);
541 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
542 &curtime, input, buffer, COUNTOF(buffer));
543 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
544 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
545 EXPECT_EQA;
546 }
547
548 static void test_GetDateFormatW(void)
549 {
550 int ret;
551 SYSTEMTIME curtime;
552 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
553 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
554
555 STRINGSW("",""); /* If flags is not zero then format must be NULL */
556 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
557 input, buffer, COUNTOF(buffer));
558 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
559 {
560 win_skip("GetDateFormatW is not implemented\n");
561 return;
562 }
563 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
564 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
565 EXPECT_EQW;
566
567 STRINGSW("",""); /* NULL buffer, len > 0 */
568 SetLastError(0xdeadbeef);
569 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
570 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
571 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
572
573 STRINGSW("",""); /* NULL buffer, len == 0 */
574 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
575 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
576 EXPECT_LENW; EXPECT_EQW;
577
578 curtime.wYear = 2002;
579 curtime.wMonth = 10;
580 curtime.wDay = 23;
581 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
582 curtime.wHour = 65432; /* Invalid */
583 curtime.wMinute = 34512; /* Invalid */
584 curtime.wSecond = 65535; /* Invalid */
585 curtime.wMilliseconds = 12345;
586 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
587 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
588 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
589 EXPECT_LENW; EXPECT_EQW;
590
591 /* Limit tests */
592
593 curtime.wYear = 1601;
594 curtime.wMonth = 1;
595 curtime.wDay = 1;
596 curtime.wDayOfWeek = 0; /* Irrelevant */
597 curtime.wHour = 0;
598 curtime.wMinute = 0;
599 curtime.wSecond = 0;
600 curtime.wMilliseconds = 0;
601 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
602 SetLastError(0xdeadbeef);
603 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
604 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
605 EXPECT_LENW; EXPECT_EQW;
606
607 curtime.wYear = 1600;
608 curtime.wMonth = 12;
609 curtime.wDay = 31;
610 curtime.wDayOfWeek = 0; /* Irrelevant */
611 curtime.wHour = 23;
612 curtime.wMinute = 59;
613 curtime.wSecond = 59;
614 curtime.wMilliseconds = 999;
615 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
616 SetLastError(0xdeadbeef);
617 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
618 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
619 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
620 }
621
622
623 #define CY_POS_LEFT 0
624 #define CY_POS_RIGHT 1
625 #define CY_POS_LEFT_SPACE 2
626 #define CY_POS_RIGHT_SPACE 3
627
628 static void test_GetCurrencyFormatA(void)
629 {
630 static char szDot[] = { '.', '\0' };
631 static char szComma[] = { ',', '\0' };
632 static char szDollar[] = { '$', '\0' };
633 int ret;
634 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
635 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
636 CURRENCYFMTA format;
637
638 memset(&format, 0, sizeof(format));
639
640 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
641 SetLastError(0xdeadbeef);
642 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
643 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
644 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
645
646 STRINGSA("23,53",""); /* Invalid character --> Error */
647 SetLastError(0xdeadbeef);
648 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
649 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
650 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
651
652 STRINGSA("--",""); /* Double '-' --> Error */
653 SetLastError(0xdeadbeef);
654 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
655 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
656 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
657
658 STRINGSA("0-",""); /* Trailing '-' --> Error */
659 SetLastError(0xdeadbeef);
660 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
661 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
662 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
663
664 STRINGSA("0..",""); /* Double '.' --> Error */
665 SetLastError(0xdeadbeef);
666 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
667 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
668 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
669
670 STRINGSA(" 0.1",""); /* Leading space --> Error */
671 SetLastError(0xdeadbeef);
672 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
673 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
674 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
675
676 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
677 SetLastError(0xdeadbeef);
678 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
679 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
680 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
681
682 STRINGSA("2353",""); /* Format and flags given --> Error */
683 SetLastError(0xdeadbeef);
684 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
685 ok( !ret, "Expected ret == 0, got %d\n", ret);
686 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
687 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
688
689 STRINGSA("2353",""); /* Invalid format --> Error */
690 SetLastError(0xdeadbeef);
691 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
692 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
693 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
694
695 STRINGSA("2353","$2,353.00"); /* Valid number */
696 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
697 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
698 EXPECT_LENA; EXPECT_EQA;
699
700 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
701 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
702 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
703 EXPECT_LENA; EXPECT_EQA;
704
705 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
706 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 EXPECT_LENA; EXPECT_EQA;
709
710 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
711 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 EXPECT_LENA; EXPECT_EQA;
714
715 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
716 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
718 EXPECT_LENA; EXPECT_EQA;
719
720 format.NumDigits = 0; /* No decimal separator */
721 format.LeadingZero = 0;
722 format.Grouping = 0; /* No grouping char */
723 format.NegativeOrder = 0;
724 format.PositiveOrder = CY_POS_LEFT;
725 format.lpDecimalSep = szDot;
726 format.lpThousandSep = szComma;
727 format.lpCurrencySymbol = szDollar;
728
729 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
730 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
731 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
732 EXPECT_LENA; EXPECT_EQA;
733
734 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
735 STRINGSA("2353","$2353.0");
736 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
737 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
738 EXPECT_LENA; EXPECT_EQA;
739
740 format.Grouping = 2; /* Group by 100's */
741 STRINGSA("2353","$23,53.0");
742 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
743 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
744 EXPECT_LENA; EXPECT_EQA;
745
746 STRINGSA("235","$235.0"); /* Grouping of a positive number */
747 format.Grouping = 3;
748 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
749 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
750 EXPECT_LENA; EXPECT_EQA;
751
752 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
753 format.NegativeOrder = 2;
754 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
755 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
756 EXPECT_LENA; EXPECT_EQA;
757
758 format.LeadingZero = 1; /* Always provide leading zero */
759 STRINGSA(".5","$0.5");
760 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
761 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
762 EXPECT_LENA; EXPECT_EQA;
763
764 format.PositiveOrder = CY_POS_RIGHT;
765 STRINGSA("1","1.0$");
766 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
767 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
768 EXPECT_LENA; EXPECT_EQA;
769
770 format.PositiveOrder = CY_POS_LEFT_SPACE;
771 STRINGSA("1","$ 1.0");
772 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
773 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
774 EXPECT_LENA; EXPECT_EQA;
775
776 format.PositiveOrder = CY_POS_RIGHT_SPACE;
777 STRINGSA("1","1.0 $");
778 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
779 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
780 EXPECT_LENA; EXPECT_EQA;
781
782 format.NegativeOrder = 0;
783 STRINGSA("-1","($1.0)");
784 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENA; EXPECT_EQA;
787
788 format.NegativeOrder = 1;
789 STRINGSA("-1","-$1.0");
790 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
791 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
792 EXPECT_LENA; EXPECT_EQA;
793
794 format.NegativeOrder = 2;
795 STRINGSA("-1","$-1.0");
796 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
797 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
798 EXPECT_LENA; EXPECT_EQA;
799
800 format.NegativeOrder = 3;
801 STRINGSA("-1","$1.0-");
802 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
803 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
804 EXPECT_LENA; EXPECT_EQA;
805
806 format.NegativeOrder = 4;
807 STRINGSA("-1","(1.0$)");
808 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
809 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
810 EXPECT_LENA; EXPECT_EQA;
811
812 format.NegativeOrder = 5;
813 STRINGSA("-1","-1.0$");
814 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
815 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
816 EXPECT_LENA; EXPECT_EQA;
817
818 format.NegativeOrder = 6;
819 STRINGSA("-1","1.0-$");
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.NegativeOrder = 7;
825 STRINGSA("-1","1.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.NegativeOrder = 8;
831 STRINGSA("-1","-1.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 format.NegativeOrder = 9;
837 STRINGSA("-1","-$ 1.0");
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 format.NegativeOrder = 10;
843 STRINGSA("-1","1.0 $-");
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.NegativeOrder = 11;
849 STRINGSA("-1","$ 1.0-");
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.NegativeOrder = 12;
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.NegativeOrder = 13;
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.NegativeOrder = 14;
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 = 15;
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
879 #define NEG_PARENS 0 /* "(1.1)" */
880 #define NEG_LEFT 1 /* "-1.1" */
881 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
882 #define NEG_RIGHT 3 /* "1.1-" */
883 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
884
885 static void test_GetNumberFormatA(void)
886 {
887 static char szDot[] = { '.', '\0' };
888 static char szComma[] = { ',', '\0' };
889 int ret;
890 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
891 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
892 NUMBERFMTA format;
893
894 memset(&format, 0, sizeof(format));
895
896 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
897 SetLastError(0xdeadbeef);
898 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
899 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
900 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
901
902 STRINGSA("23,53",""); /* Invalid character --> Error */
903 SetLastError(0xdeadbeef);
904 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
905 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
906 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
907
908 STRINGSA("--",""); /* Double '-' --> Error */
909 SetLastError(0xdeadbeef);
910 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
911 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
912 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
913
914 STRINGSA("0-",""); /* Trailing '-' --> Error */
915 SetLastError(0xdeadbeef);
916 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
917 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
918 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
919
920 STRINGSA("0..",""); /* Double '.' --> Error */
921 SetLastError(0xdeadbeef);
922 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
923 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
924 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
925
926 STRINGSA(" 0.1",""); /* Leading space --> Error */
927 SetLastError(0xdeadbeef);
928 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
929 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
930 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
931
932 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
933 SetLastError(0xdeadbeef);
934 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
935 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
936 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
937
938 STRINGSA("2353",""); /* Format and flags given --> Error */
939 SetLastError(0xdeadbeef);
940 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
941 ok( !ret, "Expected ret == 0, got %d\n", ret);
942 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
943 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
944
945 STRINGSA("2353",""); /* Invalid format --> Error */
946 SetLastError(0xdeadbeef);
947 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
948 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
949 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
950
951 STRINGSA("2353","2,353.00"); /* Valid number */
952 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
953 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
954 EXPECT_LENA; EXPECT_EQA;
955
956 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
957 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
958 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
959 EXPECT_LENA; EXPECT_EQA;
960
961 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
962 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
963 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
964 EXPECT_LENA; EXPECT_EQA;
965
966 STRINGSA("2353.1","2,353.10"); /* Valid real number */
967 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
968 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
969 EXPECT_LENA; EXPECT_EQA;
970
971 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
972 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
973 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
974 EXPECT_LENA; EXPECT_EQA;
975
976 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
977 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
978 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
979 EXPECT_LENA; EXPECT_EQA;
980
981 format.NumDigits = 0; /* No decimal separator */
982 format.LeadingZero = 0;
983 format.Grouping = 0; /* No grouping char */
984 format.NegativeOrder = 0;
985 format.lpDecimalSep = szDot;
986 format.lpThousandSep = szComma;
987
988 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
989 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
990 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
991 EXPECT_LENA; EXPECT_EQA;
992
993 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
994 STRINGSA("2353","2353.0");
995 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
996 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
997 EXPECT_LENA; EXPECT_EQA;
998
999 format.Grouping = 2; /* Group by 100's */
1000 STRINGSA("2353","23,53.0");
1001 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1002 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1003 EXPECT_LENA; EXPECT_EQA;
1004
1005 STRINGSA("235","235.0"); /* Grouping of a positive number */
1006 format.Grouping = 3;
1007 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1008 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1009 EXPECT_LENA; EXPECT_EQA;
1010
1011 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1012 format.NegativeOrder = NEG_LEFT;
1013 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1014 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1015 EXPECT_LENA; EXPECT_EQA;
1016
1017 format.LeadingZero = 1; /* Always provide leading zero */
1018 STRINGSA(".5","0.5");
1019 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1020 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1021 EXPECT_LENA; EXPECT_EQA;
1022
1023 format.NegativeOrder = NEG_PARENS;
1024 STRINGSA("-1","(1.0)");
1025 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1026 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1027 EXPECT_LENA; EXPECT_EQA;
1028
1029 format.NegativeOrder = NEG_LEFT;
1030 STRINGSA("-1","-1.0");
1031 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1032 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1033 EXPECT_LENA; EXPECT_EQA;
1034
1035 format.NegativeOrder = NEG_LEFT_SPACE;
1036 STRINGSA("-1","- 1.0");
1037 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1038 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1039 EXPECT_LENA; EXPECT_EQA;
1040
1041 format.NegativeOrder = NEG_RIGHT;
1042 STRINGSA("-1","1.0-");
1043 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1044 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1045 EXPECT_LENA; EXPECT_EQA;
1046
1047 format.NegativeOrder = NEG_RIGHT_SPACE;
1048 STRINGSA("-1","1.0 -");
1049 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1050 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1051 EXPECT_LENA; EXPECT_EQA;
1052
1053 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1054
1055 if (IsValidLocale(lcid, 0))
1056 {
1057 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1058 Expected[3] = 160; /* Non breaking space */
1059 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1060 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1061 EXPECT_LENA; EXPECT_EQA;
1062 }
1063 }
1064
1065
1066 static void test_CompareStringA(void)
1067 {
1068 int ret;
1069 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1070
1071 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1072 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1073
1074 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1075 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1076
1077 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1078 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1079
1080 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1081 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1082
1083 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1084
1085 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1086 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1087
1088 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1089 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1090
1091 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1092 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1093
1094 /* test for CompareStringA flags */
1095 SetLastError(0xdeadbeef);
1096 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1097 ok(GetLastError() == ERROR_INVALID_FLAGS,
1098 "unexpected error code %d\n", GetLastError());
1099 ok(!ret, "CompareStringA must fail with invalid flag\n");
1100
1101 SetLastError(0xdeadbeef);
1102 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1103 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1104 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1105 /* end of test for CompareStringA flags */
1106
1107 ret = lstrcmpA("", "");
1108 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1109
1110 ret = lstrcmpA(NULL, NULL);
1111 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1112
1113 ret = lstrcmpA("", NULL);
1114 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1115
1116 ret = lstrcmpA(NULL, "");
1117 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1118
1119 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
1120 ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
1121
1122 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
1123 ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
1124
1125 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
1126 ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
1127
1128 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
1129 ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
1130
1131 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
1132 ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
1133
1134 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
1135 ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
1136
1137 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
1138 ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
1139
1140 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
1141 ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
1142
1143 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
1144 ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
1145
1146 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
1147 ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
1148
1149 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
1150 ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
1151
1152 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
1153 ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
1154
1155 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
1156 ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
1157
1158 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
1159 ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
1160
1161 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
1162 ok( ret == 3, "a vs { expected 3, got %d\n", ret);
1163
1164 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
1165 ok( ret == 3, "A vs { expected 3, got %d\n", ret);
1166
1167 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
1168 ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
1169
1170 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
1171 ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
1172
1173 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
1174 ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
1175
1176 /* hyphen and apostrophe are treated differently depending on
1177 * whether SORT_STRINGSORT specified or not
1178 */
1179 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
1180 ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
1181
1182 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
1183 ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
1184
1185 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
1186 ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
1187
1188 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
1189 ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
1190
1191 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
1192 ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
1193
1194 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
1195 ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
1196
1197 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
1198 ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
1199
1200 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
1201 ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
1202
1203 if (0) { /* this requires collation table patch to make it MS compatible */
1204 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1205 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1206
1207 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1208 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1209
1210 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1211 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1212
1213 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1214 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1215
1216 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1217 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1218
1219 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1220 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1221
1222 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1223 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1224
1225 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1226 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1227
1228 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1229 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1230
1231 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1232 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1233
1234 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1235 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1236
1237 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1238 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1239 }
1240
1241 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
1242 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
1243
1244 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
1245 ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
1246
1247 /* WinXP handles embedded NULLs differently than earlier versions */
1248 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1249 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1250
1251 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1252 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1253
1254 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1255 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1256
1257 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1258 ok(ret == CSTR_EQUAL || /* win2k */
1259 ret == CSTR_GREATER_THAN,
1260 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1261
1262 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1263 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1264
1265 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1266 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1267
1268 ret = lstrcmpi("#", ".");
1269 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1270 }
1271
1272 static void test_LCMapStringA(void)
1273 {
1274 int ret, ret2;
1275 char buf[256], buf2[256];
1276 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1277 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1278 static const char symbols_stripped[] = "justateststring1";
1279
1280 SetLastError(0xdeadbeef);
1281 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1282 lower_case, -1, buf, sizeof(buf));
1283 ok(ret == lstrlenA(lower_case) + 1,
1284 "ret %d, error %d, expected value %d\n",
1285 ret, GetLastError(), lstrlenA(lower_case) + 1);
1286 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1287
1288 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1289 upper_case, -1, buf, sizeof(buf));
1290 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1291 ok(GetLastError() == ERROR_INVALID_FLAGS,
1292 "unexpected error code %d\n", GetLastError());
1293
1294 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1295 upper_case, -1, buf, sizeof(buf));
1296 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1297 ok(GetLastError() == ERROR_INVALID_FLAGS,
1298 "unexpected error code %d\n", GetLastError());
1299
1300 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1301 upper_case, -1, buf, sizeof(buf));
1302 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1303 ok(GetLastError() == ERROR_INVALID_FLAGS,
1304 "unexpected error code %d\n", GetLastError());
1305
1306 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1307 upper_case, -1, buf, sizeof(buf));
1308 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1309 ok(GetLastError() == ERROR_INVALID_FLAGS,
1310 "unexpected error code %d\n", GetLastError());
1311
1312 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1313 SetLastError(0xdeadbeef);
1314 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1315 upper_case, -1, buf, sizeof(buf));
1316 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1317 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1318
1319 /* test LCMAP_LOWERCASE */
1320 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1321 upper_case, -1, buf, sizeof(buf));
1322 ok(ret == lstrlenA(upper_case) + 1,
1323 "ret %d, error %d, expected value %d\n",
1324 ret, GetLastError(), lstrlenA(upper_case) + 1);
1325 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1326
1327 /* test LCMAP_UPPERCASE */
1328 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1329 lower_case, -1, buf, sizeof(buf));
1330 ok(ret == lstrlenA(lower_case) + 1,
1331 "ret %d, error %d, expected value %d\n",
1332 ret, GetLastError(), lstrlenA(lower_case) + 1);
1333 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1334
1335 /* test buffer overflow */
1336 SetLastError(0xdeadbeef);
1337 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1338 lower_case, -1, buf, 4);
1339 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1340 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1341
1342 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1343 lstrcpyA(buf, lower_case);
1344 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1345 buf, -1, buf, sizeof(buf));
1346 if (!ret) /* Win9x */
1347 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1348 else
1349 {
1350 ok(ret == lstrlenA(lower_case) + 1,
1351 "ret %d, error %d, expected value %d\n",
1352 ret, GetLastError(), lstrlenA(lower_case) + 1);
1353 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1354 }
1355 lstrcpyA(buf, upper_case);
1356 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1357 buf, -1, buf, sizeof(buf));
1358 if (!ret) /* Win9x */
1359 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1360 else
1361 {
1362 ok(ret == lstrlenA(upper_case) + 1,
1363 "ret %d, error %d, expected value %d\n",
1364 ret, GetLastError(), lstrlenA(lower_case) + 1);
1365 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1366 }
1367
1368 /* otherwise src == dst should fail */
1369 SetLastError(0xdeadbeef);
1370 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1371 buf, 10, buf, sizeof(buf));
1372 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1373 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1374 "unexpected error code %d\n", GetLastError());
1375 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1376
1377 /* test whether '\0' is always appended */
1378 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1379 upper_case, -1, buf, sizeof(buf));
1380 ok(ret, "LCMapStringA must succeed\n");
1381 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1382 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1383 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1384 ok(ret2, "LCMapStringA must succeed\n");
1385 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1386 ok(ret == ret2, "lengths of sort keys must be equal\n");
1387 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1388
1389 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1390 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1391 upper_case, -1, buf, sizeof(buf));
1392 ok(ret, "LCMapStringA must succeed\n");
1393 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1394 lower_case, -1, buf2, sizeof(buf2));
1395 ok(ret2, "LCMapStringA must succeed\n");
1396 ok(ret == ret2, "lengths of sort keys must be equal\n");
1397 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1398
1399 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1400 results from plain LCMAP_SORTKEY on Vista */
1401
1402 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1403 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1404 lower_case, -1, buf, sizeof(buf));
1405 ok(ret, "LCMapStringA must succeed\n");
1406 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1407 symbols_stripped, -1, buf2, sizeof(buf2));
1408 ok(ret2, "LCMapStringA must succeed\n");
1409 ok(ret == ret2, "lengths of sort keys must be equal\n");
1410 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1411
1412 /* test NORM_IGNORENONSPACE */
1413 lstrcpyA(buf, "foo");
1414 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1415 lower_case, -1, buf, sizeof(buf));
1416 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1417 lstrlenA(lower_case) + 1, ret);
1418 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1419
1420 /* test NORM_IGNORESYMBOLS */
1421 lstrcpyA(buf, "foo");
1422 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1423 lower_case, -1, buf, sizeof(buf));
1424 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1425 lstrlenA(symbols_stripped) + 1, ret);
1426 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1427
1428 /* test srclen = 0 */
1429 SetLastError(0xdeadbeef);
1430 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1431 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1432 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1433 "unexpected error code %d\n", GetLastError());
1434 }
1435
1436 static void test_LCMapStringW(void)
1437 {
1438 int ret, ret2;
1439 WCHAR buf[256], buf2[256];
1440 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1441 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};
1442 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};
1443 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1444 static const WCHAR fooW[] = {'f','o','o',0};
1445
1446 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1447 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1448 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1449 {
1450 win_skip("LCMapStringW is not implemented\n");
1451 return;
1452 }
1453 if (broken(ret))
1454 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1455 else
1456 {
1457 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1458 ok(GetLastError() == ERROR_INVALID_FLAGS,
1459 "unexpected error code %d\n", GetLastError());
1460 }
1461
1462 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1463 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1464 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1465 ok(GetLastError() == ERROR_INVALID_FLAGS,
1466 "unexpected error code %d\n", GetLastError());
1467
1468 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1469 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1470 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1471 ok(GetLastError() == ERROR_INVALID_FLAGS,
1472 "unexpected error code %d\n", GetLastError());
1473
1474 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1475 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1476 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1477 ok(GetLastError() == ERROR_INVALID_FLAGS,
1478 "unexpected error code %d\n", GetLastError());
1479
1480 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1481 SetLastError(0xdeadbeef);
1482 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1483 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1484 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1485 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1486
1487 /* test LCMAP_LOWERCASE */
1488 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1489 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1490 ok(ret == lstrlenW(upper_case) + 1,
1491 "ret %d, error %d, expected value %d\n",
1492 ret, GetLastError(), lstrlenW(upper_case) + 1);
1493 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1494
1495 /* test LCMAP_UPPERCASE */
1496 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1497 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1498 ok(ret == lstrlenW(lower_case) + 1,
1499 "ret %d, error %d, expected value %d\n",
1500 ret, GetLastError(), lstrlenW(lower_case) + 1);
1501 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1502
1503 /* test buffer overflow */
1504 SetLastError(0xdeadbeef);
1505 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1506 lower_case, -1, buf, 4);
1507 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1508 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1509
1510 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1511 lstrcpyW(buf, lower_case);
1512 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1513 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1514 ok(ret == lstrlenW(lower_case) + 1,
1515 "ret %d, error %d, expected value %d\n",
1516 ret, GetLastError(), lstrlenW(lower_case) + 1);
1517 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1518
1519 lstrcpyW(buf, upper_case);
1520 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1521 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1522 ok(ret == lstrlenW(upper_case) + 1,
1523 "ret %d, error %d, expected value %d\n",
1524 ret, GetLastError(), lstrlenW(lower_case) + 1);
1525 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1526
1527 /* otherwise src == dst should fail */
1528 SetLastError(0xdeadbeef);
1529 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1530 buf, 10, buf, sizeof(buf));
1531 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1532 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1533 "unexpected error code %d\n", GetLastError());
1534 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1535
1536 /* test whether '\0' is always appended */
1537 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1538 upper_case, -1, buf, sizeof(buf));
1539 ok(ret, "LCMapStringW must succeed\n");
1540 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1541 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1542 ok(ret, "LCMapStringW must succeed\n");
1543 ok(ret == ret2, "lengths of sort keys must be equal\n");
1544 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1545
1546 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1547 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1548 upper_case, -1, buf, sizeof(buf));
1549 ok(ret, "LCMapStringW must succeed\n");
1550 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1551 lower_case, -1, buf2, sizeof(buf2));
1552 ok(ret2, "LCMapStringW must succeed\n");
1553 ok(ret == ret2, "lengths of sort keys must be equal\n");
1554 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1555
1556 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1557 results from plain LCMAP_SORTKEY on Vista */
1558
1559 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1560 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1561 lower_case, -1, buf, sizeof(buf));
1562 ok(ret, "LCMapStringW must succeed\n");
1563 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1564 symbols_stripped, -1, buf2, sizeof(buf2));
1565 ok(ret2, "LCMapStringW must succeed\n");
1566 ok(ret == ret2, "lengths of sort keys must be equal\n");
1567 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1568
1569 /* test NORM_IGNORENONSPACE */
1570 lstrcpyW(buf, fooW);
1571 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1572 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1573 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1574 lstrlenW(lower_case) + 1, ret);
1575 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1576
1577 /* test NORM_IGNORESYMBOLS */
1578 lstrcpyW(buf, fooW);
1579 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1580 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1581 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1582 lstrlenW(symbols_stripped) + 1, ret);
1583 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1584
1585 /* test srclen = 0 */
1586 SetLastError(0xdeadbeef);
1587 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1588 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1589 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1590 "unexpected error code %d\n", GetLastError());
1591 }
1592
1593 /* this requires collation table patch to make it MS compatible */
1594 static const char * const strings_sorted[] =
1595 {
1596 "'",
1597 "-",
1598 "!",
1599 "\"",
1600 ".",
1601 ":",
1602 "\\",
1603 "_",
1604 "`",
1605 "{",
1606 "}",
1607 "+",
1608 "0",
1609 "1",
1610 "2",
1611 "3",
1612 "4",
1613 "5",
1614 "6",
1615 "7",
1616 "8",
1617 "9",
1618 "a",
1619 "A",
1620 "b",
1621 "B",
1622 "c",
1623 "C"
1624 };
1625
1626 static const char * const strings[] =
1627 {
1628 "C",
1629 "\"",
1630 "9",
1631 "'",
1632 "}",
1633 "-",
1634 "7",
1635 "+",
1636 "`",
1637 "1",
1638 "a",
1639 "5",
1640 "\\",
1641 "8",
1642 "B",
1643 "3",
1644 "_",
1645 "6",
1646 "{",
1647 "2",
1648 "c",
1649 "4",
1650 "!",
1651 "0",
1652 "A",
1653 ":",
1654 "b",
1655 "."
1656 };
1657
1658 static int compare_string1(const void *e1, const void *e2)
1659 {
1660 const char *s1 = *(const char *const *)e1;
1661 const char *s2 = *(const char *const *)e2;
1662
1663 return lstrcmpA(s1, s2);
1664 }
1665
1666 static int compare_string2(const void *e1, const void *e2)
1667 {
1668 const char *s1 = *(const char *const *)e1;
1669 const char *s2 = *(const char *const *)e2;
1670
1671 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1672 }
1673
1674 static int compare_string3(const void *e1, const void *e2)
1675 {
1676 const char *s1 = *(const char *const *)e1;
1677 const char *s2 = *(const char *const *)e2;
1678 char key1[256], key2[256];
1679
1680 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1681 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1682 return strcmp(key1, key2);
1683 }
1684
1685 static void test_sorting(void)
1686 {
1687 char buf[256];
1688 char **str_buf = (char **)buf;
1689 int i;
1690
1691 assert(sizeof(buf) >= sizeof(strings));
1692
1693 /* 1. sort using lstrcmpA */
1694 memcpy(buf, strings, sizeof(strings));
1695 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1696 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1697 {
1698 ok(!strcmp(strings_sorted[i], str_buf[i]),
1699 "qsort using lstrcmpA failed for element %d\n", i);
1700 }
1701 /* 2. sort using CompareStringA */
1702 memcpy(buf, strings, sizeof(strings));
1703 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1704 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1705 {
1706 ok(!strcmp(strings_sorted[i], str_buf[i]),
1707 "qsort using CompareStringA failed for element %d\n", i);
1708 }
1709 /* 3. sort using sort keys */
1710 memcpy(buf, strings, sizeof(strings));
1711 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1712 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1713 {
1714 ok(!strcmp(strings_sorted[i], str_buf[i]),
1715 "qsort using sort keys failed for element %d\n", i);
1716 }
1717 }
1718
1719 static void test_FoldStringA(void)
1720 {
1721 int ret, i, j;
1722 BOOL is_special;
1723 char src[256], dst[256];
1724 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1725 static const char digits_dst[] = { '1','2','3','\0' };
1726 static const char composite_src[] =
1727 {
1728 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1729 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1730 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1731 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1732 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1733 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1734 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1735 0xfb,0xfc,0xfd,0xff,'\0'
1736 };
1737 static const char composite_dst[] =
1738 {
1739 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1740 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1741 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1742 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1743 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1744 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1745 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1746 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1747 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1748 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1749 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1750 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1751 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1752 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1753 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1754 };
1755 static const char composite_dst_alt[] =
1756 {
1757 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1758 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1759 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1760 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1761 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1762 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1763 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1764 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1765 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1766 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1767 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1768 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1769 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1770 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1771 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1772 };
1773 static const char ligatures_src[] =
1774 {
1775 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1776 };
1777 static const char ligatures_dst[] =
1778 {
1779 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1780 };
1781 static const struct special
1782 {
1783 char src;
1784 char dst[4];
1785 } foldczone_special[] =
1786 {
1787 /* src dst */
1788 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1789 { 0x98, { 0x20, 0x7e, 0x00 } },
1790 { 0x99, { 0x54, 0x4d, 0x00 } },
1791 { 0xa0, { 0x20, 0x00 } },
1792 { 0xa8, { 0x20, 0xa8, 0x00 } },
1793 { 0xaa, { 0x61, 0x00 } },
1794 { 0xaf, { 0x20, 0xaf, 0x00 } },
1795 { 0xb2, { 0x32, 0x00 } },
1796 { 0xb3, { 0x33, 0x00 } },
1797 { 0xb4, { 0x20, 0xb4, 0x00 } },
1798 { 0xb8, { 0x20, 0xb8, 0x00 } },
1799 { 0xb9, { 0x31, 0x00 } },
1800 { 0xba, { 0x6f, 0x00 } },
1801 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1802 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1803 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1804 { 0x00 }
1805 };
1806
1807 if (!pFoldStringA)
1808 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1809
1810 /* these tests are locale specific */
1811 if (GetACP() != 1252)
1812 {
1813 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1814 return;
1815 }
1816
1817 /* MAP_FOLDDIGITS */
1818 SetLastError(0);
1819 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1820 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1821 {
1822 win_skip("FoldStringA is not implemented\n");
1823 return;
1824 }
1825 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1826 ok(strcmp(dst, digits_dst) == 0,
1827 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1828 for (i = 1; i < 256; i++)
1829 {
1830 if (!strchr(digits_src, i))
1831 {
1832 src[0] = i;
1833 src[1] = '\0';
1834 SetLastError(0);
1835 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1836 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1837 ok(dst[0] == src[0],
1838 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1839 }
1840 }
1841
1842 /* MAP_EXPAND_LIGATURES */
1843 SetLastError(0);
1844 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1845 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1846 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1847 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1848 ok(strcmp(dst, ligatures_dst) == 0,
1849 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1850 for (i = 1; i < 256; i++)
1851 {
1852 if (!strchr(ligatures_src, i))
1853 {
1854 src[0] = i;
1855 src[1] = '\0';
1856 SetLastError(0);
1857 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1858 if (ret == 3)
1859 {
1860 /* Vista */
1861 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1862 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1863 "Got %s for %d\n", dst, i);
1864 }
1865 else
1866 {
1867 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1868 ok(dst[0] == src[0],
1869 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1870 }
1871 }
1872 }
1873 }
1874
1875 /* MAP_COMPOSITE */
1876 SetLastError(0);
1877 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1878 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1879 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1880 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1881 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1882
1883 for (i = 1; i < 256; i++)
1884 {
1885 if (!strchr(composite_src, i))
1886 {
1887 src[0] = i;
1888 src[1] = '\0';
1889 SetLastError(0);
1890 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1891 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1892 ok(dst[0] == src[0],
1893 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1894 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1895 }
1896 }
1897
1898 /* MAP_FOLDCZONE */
1899 for (i = 1; i < 256; i++)
1900 {
1901 src[0] = i;
1902 src[1] = '\0';
1903 SetLastError(0);
1904 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1905 is_special = FALSE;
1906 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1907 {
1908 if (foldczone_special[j].src == src[0])
1909 {
1910 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1911 "Expected ret == 2 or %d, got %d, error %d\n",
1912 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
1913 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
1914 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
1915 (unsigned char)src[0]);
1916 is_special = TRUE;
1917 }
1918 }
1919 if (! is_special)
1920 {
1921 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1922 ok(src[0] == dst[0],
1923 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1924 (unsigned char)src[0], (unsigned char)dst[0]);
1925 }
1926 }
1927
1928 /* MAP_PRECOMPOSED */
1929 for (i = 1; i < 256; i++)
1930 {
1931 src[0] = i;
1932 src[1] = '\0';
1933 SetLastError(0);
1934 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1935 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1936 ok(src[0] == dst[0],
1937 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1938 (unsigned char)src[0], (unsigned char)dst[0]);
1939 }
1940 }
1941
1942 static void test_FoldStringW(void)
1943 {
1944 int ret;
1945 unsigned int i, j;
1946 WCHAR src[256], dst[256], ch, prev_ch = 1;
1947 static const DWORD badFlags[] =
1948 {
1949 0,
1950 MAP_PRECOMPOSED|MAP_COMPOSITE,
1951 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1952 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1953 };
1954 /* Ranges of digits 0-9 : Must be sorted! */
1955 static const WCHAR digitRanges[] =
1956 {
1957 0x0030, /* '0'-'9' */
1958 0x0660, /* Eastern Arabic */
1959 0x06F0, /* Arabic - Hindu */
1960 0x0966, /* Devengari */
1961 0x09E6, /* Bengalii */
1962 0x0A66, /* Gurmukhi */
1963 0x0AE6, /* Gujarati */
1964 0x0B66, /* Oriya */
1965 0x0BE6, /* Tamil - No 0 */
1966 0x0C66, /* Telugu */
1967 0x0CE6, /* Kannada */
1968 0x0D66, /* Maylayalam */
1969 0x0E50, /* Thai */
1970 0x0ED0, /* Laos */
1971 0x0F29, /* Tibet - 0 is out of sequence */
1972 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1973 0x2080, /* Subscript */
1974 0x245F, /* Circled - 0 is out of sequence */
1975 0x2473, /* Bracketed */
1976 0x2487, /* Full stop */
1977 0x2775, /* Inverted circled - No 0 */
1978 0x277F, /* Patterned circled - No 0 */
1979 0x2789, /* Inverted Patterned circled - No 0 */
1980 0x3020, /* Hangzhou */
1981 0xff10, /* Pliene chasse (?) */
1982 0xffff /* Terminator */
1983 };
1984 /* Digits which are represented, but out of sequence */
1985 static const WCHAR outOfSequenceDigits[] =
1986 {
1987 0xB9, /* Superscript 1 */
1988 0xB2, /* Superscript 2 */
1989 0xB3, /* Superscript 3 */
1990 0x0F33, /* Tibetan half zero */
1991 0x24EA, /* Circled 0 */
1992 0x3007, /* Ideographic number zero */
1993 '\0' /* Terminator */
1994 };
1995 /* Digits in digitRanges for which no representation is available */
1996 static const WCHAR noDigitAvailable[] =
1997 {
1998 0x0BE6, /* No Tamil 0 */
1999 0x0F29, /* No Tibetan half zero (out of sequence) */
2000 0x2473, /* No Bracketed 0 */
2001 0x2487, /* No 0 Full stop */
2002 0x2775, /* No inverted circled 0 */
2003 0x277F, /* No patterned circled */
2004 0x2789, /* No inverted Patterned circled */
2005 0x3020, /* No Hangzhou 0 */
2006 '\0' /* Terminator */
2007 };
2008 static const WCHAR foldczone_src[] =
2009 {
2010 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2011 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2012 };
2013 static const WCHAR foldczone_dst[] =
2014 {
2015 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2016 };
2017 static const WCHAR ligatures_src[] =
2018 {
2019 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2020 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2021 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2022 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2023 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2024 0xfb04, 0xfb05, 0xfb06, '\0'
2025 };
2026 static const WCHAR ligatures_dst[] =
2027 {
2028 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2029 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2030 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2031 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2032 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2033 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2034 };
2035
2036 if (!pFoldStringW)
2037 {
2038 win_skip("FoldStringW is not available\n");
2039 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2040 }
2041
2042 /* Invalid flag combinations */
2043 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2044 {
2045 src[0] = dst[0] = '\0';
2046 SetLastError(0);
2047 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2048 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2049 {
2050 win_skip("FoldStringW is not implemented\n");
2051 return;
2052 }
2053 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2054 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2055 }
2056
2057 /* src & dst cannot be the same */
2058 SetLastError(0);
2059 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2060 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2061 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2062
2063 /* src can't be NULL */
2064 SetLastError(0);
2065 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2066 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2067 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2068
2069 /* srclen can't be 0 */
2070 SetLastError(0);
2071 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2072 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2073 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2074
2075 /* dstlen can't be < 0 */
2076 SetLastError(0);
2077 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2078 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2079 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2080
2081 /* Ret includes terminating NUL which is appended if srclen = -1 */
2082 SetLastError(0);
2083 src[0] = 'A';
2084 src[1] = '\0';
2085 dst[0] = '\0';
2086 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2087 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2088 ok(dst[0] == 'A' && dst[1] == '\0',
2089 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2090 'A', '\0', ret, dst[0], dst[1], GetLastError());
2091
2092 /* If size is given, result is not NUL terminated */
2093 SetLastError(0);
2094 src[0] = 'A';
2095 src[1] = 'A';
2096 dst[0] = 'X';
2097 dst[1] = 'X';
2098 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2099 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2100 ok(dst[0] == 'A' && dst[1] == 'X',
2101 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2102 'A','X', ret, dst[0], dst[1], GetLastError());
2103
2104 /* MAP_FOLDDIGITS */
2105 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2106 {
2107 /* Check everything before this range */
2108 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2109 {
2110 SetLastError(0);
2111 src[0] = ch;
2112 src[1] = dst[0] = '\0';
2113 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2114 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2115
2116 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2117 /* Wine (correctly) maps all Unicode 4.0+ digits */
2118 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
2119 (ch >= 0x1369 && ch <= 0x1371),
2120 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2121 }
2122
2123 if (digitRanges[j] == 0xffff)
2124 break; /* Finished the whole code point space */
2125
2126 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2127 {
2128 WCHAR c;
2129
2130 /* Map out of sequence characters */
2131 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2132 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2133 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2134 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2135 else c = ch;
2136 SetLastError(0);
2137 src[0] = c;
2138 src[1] = dst[0] = '\0';
2139 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2140 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2141
2142 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2143 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2144 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2145 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2146 strchrW(noDigitAvailable, c),
2147 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2148 ch, '0' + digitRanges[j] - ch, dst[0]);
2149 }
2150 prev_ch = ch;
2151 }
2152
2153 /* MAP_FOLDCZONE */
2154 SetLastError(0);
2155 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2156 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2157 "Got %d, error %d\n", ret, GetLastError());
2158 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2159 "MAP_FOLDCZONE: Expanded incorrectly\n");
2160
2161 /* MAP_EXPAND_LIGATURES */
2162 SetLastError(0);
2163 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2164 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2165 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2166 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2167 "Got %d, error %d\n", ret, GetLastError());
2168 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2169 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2170 }
2171
2172 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2173 }
2174
2175
2176
2177 #define LCID_OK(l) \
2178 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2179 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2180 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2181 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2182 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2183
2184 static void test_ConvertDefaultLocale(void)
2185 {
2186 LCID lcid;
2187
2188 /* Doesn't change lcid, even if non default sublang/sort used */
2189 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2190 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2191 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2192 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2193
2194 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2195 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2196 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2197 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2198 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2199
2200 /* Invariant language is not treated specially */
2201 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2202
2203 /* User/system default languages alone are not mapped */
2204 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2205 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2206
2207 /* Default lcids */
2208 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2209 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2210 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2211 }
2212
2213 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2214 DWORD dwFlags, LONG_PTR lParam)
2215 {
2216 trace("%08x, %s, %s, %08x, %08lx\n",
2217 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2218
2219 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2220 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2221
2222 /* If lParam is one, we are calling with flags defaulted from 0 */
2223 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2224 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2225
2226 return TRUE;
2227 }
2228
2229 static void test_EnumSystemLanguageGroupsA(void)
2230 {
2231 BOOL ret;
2232
2233 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2234 {
2235 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2236 return;
2237 }
2238
2239 /* No enumeration proc */
2240 SetLastError(0);
2241 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2242 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2243 {
2244 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2245 return;
2246 }
2247 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2248 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2249
2250 /* Invalid flags */
2251 SetLastError(0);
2252 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2253 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2254
2255 /* No flags - defaults to LGRPID_INSTALLED */
2256 SetLastError(0xdeadbeef);
2257 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2258 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2259
2260 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2261 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2262 }
2263
2264
2265 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2266 LONG_PTR lParam)
2267 {
2268 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2269
2270 /* invalid locale enumerated on some platforms */
2271 if (lcid == 0)
2272 return TRUE;
2273
2274 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2275 "Enumerated grp %d not valid\n", lgrpid);
2276 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2277 "Enumerated grp locale %d not valid\n", lcid);
2278 return TRUE;
2279 }
2280
2281 static void test_EnumLanguageGroupLocalesA(void)
2282 {
2283 BOOL ret;
2284
2285 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2286 {
2287 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2288 return;
2289 }
2290
2291 /* No enumeration proc */
2292 SetLastError(0);
2293 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2294 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2295 {
2296 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2297 return;
2298 }
2299 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2300 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2301
2302 /* lgrpid too small */
2303 SetLastError(0);
2304 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2305 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2306 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2307
2308 /* lgrpid too big */
2309 SetLastError(0);
2310 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2311 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2312 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2313
2314 /* dwFlags is reserved */
2315 SetLastError(0);
2316 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2317 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2318 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2319
2320 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2321 }
2322
2323 static void test_SetLocaleInfoA(void)
2324 {
2325 BOOL bRet;
2326 LCID lcid = GetUserDefaultLCID();
2327
2328 /* Null data */
2329 SetLastError(0);
2330 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2331 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2332 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2333
2334 /* IDATE */
2335 SetLastError(0);
2336 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2337 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2338 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2339
2340 /* ILDATE */
2341 SetLastError(0);
2342 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2343 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2344 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2345 }
2346
2347 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2348 {
2349 trace("%s %08lx\n", value, lParam);
2350 return(TRUE);
2351 }
2352
2353 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2354 {
2355 ok(!enumCount, "callback called again unexpected\n");
2356 enumCount++;
2357 return(FALSE);
2358 }
2359
2360 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2361 {
2362 ok(0,"callback called unexpected\n");
2363 return(FALSE);
2364 }
2365
2366 static void test_EnumUILanguageA(void)
2367 {
2368 BOOL ret;
2369 if (!pEnumUILanguagesA) {
2370 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2371 return;
2372 }
2373
2374 SetLastError(ERROR_SUCCESS);
2375 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2376 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2377 {
2378 win_skip("EnumUILanguagesA is not implemented\n");
2379 return;
2380 }
2381 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2382
2383 enumCount = 0;
2384 SetLastError(ERROR_SUCCESS);
2385 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2386 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2387
2388 SetLastError(ERROR_SUCCESS);
2389 ret = pEnumUILanguagesA(NULL, 0, 0);
2390 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2391 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2392 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2393
2394 SetLastError(ERROR_SUCCESS);
2395 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2396 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2397 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2398
2399 SetLastError(ERROR_SUCCESS);
2400 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2401 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2402 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2403 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2404 }
2405
2406 static char date_fmt_buf[1024];
2407
2408 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2409 {
2410 lstrcatA(date_fmt_buf, fmt);
2411 lstrcatA(date_fmt_buf, "\n");
2412 return TRUE;
2413 }
2414
2415 static void test_EnumDateFormatsA(void)
2416 {
2417 char *p, buf[256];
2418 BOOL ret;
2419 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2420
2421 trace("EnumDateFormatsA 0\n");
2422 date_fmt_buf[0] = 0;
2423 SetLastError(0xdeadbeef);
2424 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2425 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2426 {
2427 win_skip("0 for dwFlags is not supported\n");
2428 }
2429 else
2430 {
2431 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2432 trace("%s\n", date_fmt_buf);
2433 /* test the 1st enumerated format */
2434 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2435 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2436 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2437 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2438 }
2439
2440 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2441 date_fmt_buf[0] = 0;
2442 SetLastError(0xdeadbeef);
2443 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2444 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2445 {
2446 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2447 }
2448 else
2449 {
2450 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2451 trace("%s\n", date_fmt_buf);
2452 /* test the 1st enumerated format */
2453 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2454 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2455 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2456 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2457 }
2458
2459 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2460 date_fmt_buf[0] = 0;
2461 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2462 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2463 trace("%s\n", date_fmt_buf);
2464 /* test the 1st enumerated format */
2465 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2466 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2467 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2468 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2469
2470 trace("EnumDateFormatsA DATE_LONGDATE\n");
2471 date_fmt_buf[0] = 0;
2472 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2473 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2474 trace("%s\n", date_fmt_buf);
2475 /* test the 1st enumerated format */
2476 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2477 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2478 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2479 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2480
2481 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2482 date_fmt_buf[0] = 0;
2483 SetLastError(0xdeadbeef);
2484 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2485 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2486 {
2487 skip("DATE_YEARMONTH is only present on W2K and later\n");
2488 return;
2489 }
2490 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2491 trace("%s\n", date_fmt_buf);
2492 /* test the 1st enumerated format */
2493 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2494 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2495 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2496 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2497 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2498 }
2499
2500 static void test_EnumTimeFormatsA(void)
2501 {
2502 char *p, buf[256];
2503 BOOL ret;
2504 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2505
2506 trace("EnumTimeFormatsA 0\n");
2507 date_fmt_buf[0] = 0;
2508 ret = EnumTimeFormatsA