77fae8b8b058fbc131c26de6d30b285015ed0a62
[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 format.LeadingZero = 1; /* Always provide leading zero */
747 STRINGSA(".5","$0.5");
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 format.PositiveOrder = CY_POS_RIGHT;
753 STRINGSA("1","1.0$");
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.PositiveOrder = CY_POS_LEFT_SPACE;
759 STRINGSA("1","$ 1.0");
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_SPACE;
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.NegativeOrder = 0;
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.NegativeOrder = 1;
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 = 2;
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 = 3;
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 = 4;
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 = 5;
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 = 6;
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 = 7;
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 = 8;
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 = 9;
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 = 10;
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 = 11;
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 = 12;
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 = 13;
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 = 14;
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 = 15;
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
867 #define NEG_PARENS 0 /* "(1.1)" */
868 #define NEG_LEFT 1 /* "-1.1" */
869 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
870 #define NEG_RIGHT 3 /* "1.1-" */
871 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
872
873 static void test_GetNumberFormatA(void)
874 {
875 static char szDot[] = { '.', '\0' };
876 static char szComma[] = { ',', '\0' };
877 int ret;
878 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
879 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
880 NUMBERFMTA format;
881
882 memset(&format, 0, sizeof(format));
883
884 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
885 SetLastError(0xdeadbeef);
886 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
887 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
888 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
889
890 STRINGSA("23,53",""); /* Invalid character --> Error */
891 SetLastError(0xdeadbeef);
892 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
893 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
894 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
895
896 STRINGSA("--",""); /* Double '-' --> Error */
897 SetLastError(0xdeadbeef);
898 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
899 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
900 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
901
902 STRINGSA("0-",""); /* Trailing '-' --> 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("0..",""); /* 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.1",""); /* Leading space --> 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("1234","1"); /* Length too small --> Write up to length chars */
921 SetLastError(0xdeadbeef);
922 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
923 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
924 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
925
926 STRINGSA("2353",""); /* Format and flags given --> Error */
927 SetLastError(0xdeadbeef);
928 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
929 ok( !ret, "Expected ret == 0, got %d\n", ret);
930 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
931 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
932
933 STRINGSA("2353",""); /* Invalid format --> Error */
934 SetLastError(0xdeadbeef);
935 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
936 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
937 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
938
939 STRINGSA("2353","2,353.00"); /* Valid number */
940 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
941 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942 EXPECT_LENA; EXPECT_EQA;
943
944 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
945 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 EXPECT_LENA; EXPECT_EQA;
948
949 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
950 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
951 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
952 EXPECT_LENA; EXPECT_EQA;
953
954 STRINGSA("2353.1","2,353.10"); /* Valid real number */
955 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
956 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
957 EXPECT_LENA; EXPECT_EQA;
958
959 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
960 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
961 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
962 EXPECT_LENA; EXPECT_EQA;
963
964 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
965 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
966 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
967 EXPECT_LENA; EXPECT_EQA;
968
969 format.NumDigits = 0; /* No decimal separator */
970 format.LeadingZero = 0;
971 format.Grouping = 0; /* No grouping char */
972 format.NegativeOrder = 0;
973 format.lpDecimalSep = szDot;
974 format.lpThousandSep = szComma;
975
976 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
977 ret = GetNumberFormatA(lcid, 0, input, &format, 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 = 1; /* 1 DP --> Expect decimal separator */
982 STRINGSA("2353","2353.0");
983 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
984 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
985 EXPECT_LENA; EXPECT_EQA;
986
987 format.Grouping = 2; /* Group by 100's */
988 STRINGSA("2353","23,53.0");
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.LeadingZero = 1; /* Always provide leading zero */
994 STRINGSA(".5","0.5");
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.NegativeOrder = NEG_PARENS;
1000 STRINGSA("-1","(1.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 format.NegativeOrder = NEG_LEFT;
1006 STRINGSA("-1","-1.0");
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 format.NegativeOrder = NEG_LEFT_SPACE;
1012 STRINGSA("-1","- 1.0");
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.NegativeOrder = NEG_RIGHT;
1018 STRINGSA("-1","1.0-");
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_RIGHT_SPACE;
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 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1030
1031 if (IsValidLocale(lcid, 0))
1032 {
1033 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1034 Expected[3] = 160; /* Non breaking space */
1035 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1036 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1037 EXPECT_LENA; EXPECT_EQA;
1038 }
1039 }
1040
1041
1042 static void test_CompareStringA(void)
1043 {
1044 int ret;
1045 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1046
1047 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1048 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1049
1050 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1051 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1052
1053 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1054 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1055
1056 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1057 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1058
1059 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1060
1061 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1062 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1063
1064 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1065 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1066
1067 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1068 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1069
1070 /* test for CompareStringA flags */
1071 SetLastError(0xdeadbeef);
1072 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1073 ok(GetLastError() == ERROR_INVALID_FLAGS,
1074 "unexpected error code %d\n", GetLastError());
1075 ok(!ret, "CompareStringA must fail with invalid flag\n");
1076
1077 SetLastError(0xdeadbeef);
1078 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1079 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1080 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1081 /* end of test for CompareStringA flags */
1082
1083 ret = lstrcmpA("", "");
1084 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1085
1086 ret = lstrcmpA(NULL, NULL);
1087 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1088
1089 ret = lstrcmpA("", NULL);
1090 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1091
1092 ret = lstrcmpA(NULL, "");
1093 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1094
1095 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
1096 ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
1097
1098 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
1099 ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
1100
1101 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
1102 ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
1103
1104 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
1105 ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
1106
1107 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
1108 ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
1109
1110 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
1111 ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
1112
1113 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
1114 ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
1115
1116 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
1117 ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
1118
1119 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
1120 ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
1121
1122 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
1123 ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
1124
1125 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
1126 ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
1127
1128 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
1129 ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
1130
1131 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
1132 ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
1133
1134 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
1135 ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
1136
1137 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
1138 ok( ret == 3, "a vs { expected 3, got %d\n", ret);
1139
1140 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
1141 ok( ret == 3, "A vs { expected 3, got %d\n", ret);
1142
1143 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
1144 ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
1145
1146 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
1147 ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
1148
1149 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
1150 ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
1151
1152 /* hyphen and apostrophe are treated differently depending on
1153 * whether SORT_STRINGSORT specified or not
1154 */
1155 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
1156 ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
1157
1158 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
1159 ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
1160
1161 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
1162 ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
1163
1164 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
1165 ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
1166
1167 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
1168 ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
1169
1170 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
1171 ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
1172
1173 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
1174 ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
1175
1176 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
1177 ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
1178
1179 if (0) { /* this requires collation table patch to make it MS compatible */
1180 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1181 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1182
1183 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1184 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1185
1186 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1187 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1188
1189 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1190 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1191
1192 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1193 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1194
1195 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1196 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1197
1198 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1199 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1200
1201 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1202 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1203
1204 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1205 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1206
1207 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1208 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1209
1210 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1211 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1212
1213 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1214 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1215 }
1216
1217 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
1218 ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
1219
1220 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
1221 ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
1222
1223 /* WinXP handles embedded NULLs differently than earlier versions */
1224 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1225 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1226
1227 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1228 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1229
1230 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1231 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1232
1233 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1234 ok(ret == CSTR_EQUAL || /* win2k */
1235 ret == CSTR_GREATER_THAN,
1236 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1237
1238 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1239 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1240
1241 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1242 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1243
1244 ret = lstrcmpi("#", ".");
1245 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1246 }
1247
1248 static void test_LCMapStringA(void)
1249 {
1250 int ret, ret2;
1251 char buf[256], buf2[256];
1252 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1253 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1254 static const char symbols_stripped[] = "justateststring1";
1255
1256 SetLastError(0xdeadbeef);
1257 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1258 lower_case, -1, buf, sizeof(buf));
1259 ok(ret == lstrlenA(lower_case) + 1,
1260 "ret %d, error %d, expected value %d\n",
1261 ret, GetLastError(), lstrlenA(lower_case) + 1);
1262 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1263
1264 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1265 upper_case, -1, buf, sizeof(buf));
1266 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1267 ok(GetLastError() == ERROR_INVALID_FLAGS,
1268 "unexpected error code %d\n", GetLastError());
1269
1270 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1271 upper_case, -1, buf, sizeof(buf));
1272 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1273 ok(GetLastError() == ERROR_INVALID_FLAGS,
1274 "unexpected error code %d\n", GetLastError());
1275
1276 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1277 upper_case, -1, buf, sizeof(buf));
1278 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1279 ok(GetLastError() == ERROR_INVALID_FLAGS,
1280 "unexpected error code %d\n", GetLastError());
1281
1282 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1283 upper_case, -1, buf, sizeof(buf));
1284 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1285 ok(GetLastError() == ERROR_INVALID_FLAGS,
1286 "unexpected error code %d\n", GetLastError());
1287
1288 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1289 SetLastError(0xdeadbeef);
1290 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1291 upper_case, -1, buf, sizeof(buf));
1292 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1293 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1294
1295 /* test LCMAP_LOWERCASE */
1296 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1297 upper_case, -1, buf, sizeof(buf));
1298 ok(ret == lstrlenA(upper_case) + 1,
1299 "ret %d, error %d, expected value %d\n",
1300 ret, GetLastError(), lstrlenA(upper_case) + 1);
1301 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1302
1303 /* test LCMAP_UPPERCASE */
1304 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1305 lower_case, -1, buf, sizeof(buf));
1306 ok(ret == lstrlenA(lower_case) + 1,
1307 "ret %d, error %d, expected value %d\n",
1308 ret, GetLastError(), lstrlenA(lower_case) + 1);
1309 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1310
1311 /* test buffer overflow */
1312 SetLastError(0xdeadbeef);
1313 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1314 lower_case, -1, buf, 4);
1315 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1316 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1317
1318 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1319 lstrcpyA(buf, lower_case);
1320 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1321 buf, -1, buf, sizeof(buf));
1322 if (!ret) /* Win9x */
1323 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1324 else
1325 {
1326 ok(ret == lstrlenA(lower_case) + 1,
1327 "ret %d, error %d, expected value %d\n",
1328 ret, GetLastError(), lstrlenA(lower_case) + 1);
1329 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1330 }
1331 lstrcpyA(buf, upper_case);
1332 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1333 buf, -1, buf, sizeof(buf));
1334 if (!ret) /* Win9x */
1335 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1336 else
1337 {
1338 ok(ret == lstrlenA(upper_case) + 1,
1339 "ret %d, error %d, expected value %d\n",
1340 ret, GetLastError(), lstrlenA(lower_case) + 1);
1341 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1342 }
1343
1344 /* otherwise src == dst should fail */
1345 SetLastError(0xdeadbeef);
1346 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1347 buf, 10, buf, sizeof(buf));
1348 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1349 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1350 "unexpected error code %d\n", GetLastError());
1351 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1352
1353 /* test whether '\0' is always appended */
1354 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1355 upper_case, -1, buf, sizeof(buf));
1356 ok(ret, "LCMapStringA must succeed\n");
1357 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1358 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1359 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1360 ok(ret2, "LCMapStringA must succeed\n");
1361 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1362 ok(ret == ret2, "lengths of sort keys must be equal\n");
1363 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1364
1365 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1366 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1367 upper_case, -1, buf, sizeof(buf));
1368 ok(ret, "LCMapStringA must succeed\n");
1369 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1370 lower_case, -1, buf2, sizeof(buf2));
1371 ok(ret2, "LCMapStringA must succeed\n");
1372 ok(ret == ret2, "lengths of sort keys must be equal\n");
1373 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1374
1375 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1376 results from plain LCMAP_SORTKEY on Vista */
1377
1378 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1379 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1380 lower_case, -1, buf, sizeof(buf));
1381 ok(ret, "LCMapStringA must succeed\n");
1382 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1383 symbols_stripped, -1, buf2, sizeof(buf2));
1384 ok(ret2, "LCMapStringA must succeed\n");
1385 ok(ret == ret2, "lengths of sort keys must be equal\n");
1386 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1387
1388 /* test NORM_IGNORENONSPACE */
1389 lstrcpyA(buf, "foo");
1390 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1391 lower_case, -1, buf, sizeof(buf));
1392 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1393 lstrlenA(lower_case) + 1, ret);
1394 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1395
1396 /* test NORM_IGNORESYMBOLS */
1397 lstrcpyA(buf, "foo");
1398 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1399 lower_case, -1, buf, sizeof(buf));
1400 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1401 lstrlenA(symbols_stripped) + 1, ret);
1402 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1403
1404 /* test srclen = 0 */
1405 SetLastError(0xdeadbeef);
1406 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1407 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1408 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1409 "unexpected error code %d\n", GetLastError());
1410 }
1411
1412 static void test_LCMapStringW(void)
1413 {
1414 int ret, ret2;
1415 WCHAR buf[256], buf2[256];
1416 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1417 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};
1418 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};
1419 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1420 static const WCHAR fooW[] = {'f','o','o',0};
1421
1422 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1423 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1424 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1425 {
1426 win_skip("LCMapStringW is not implemented\n");
1427 return;
1428 }
1429 if (broken(ret))
1430 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1431 else
1432 {
1433 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1434 ok(GetLastError() == ERROR_INVALID_FLAGS,
1435 "unexpected error code %d\n", GetLastError());
1436 }
1437
1438 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1439 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1440 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1441 ok(GetLastError() == ERROR_INVALID_FLAGS,
1442 "unexpected error code %d\n", GetLastError());
1443
1444 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1445 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1446 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1447 ok(GetLastError() == ERROR_INVALID_FLAGS,
1448 "unexpected error code %d\n", GetLastError());
1449
1450 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1451 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1452 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1453 ok(GetLastError() == ERROR_INVALID_FLAGS,
1454 "unexpected error code %d\n", GetLastError());
1455
1456 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1457 SetLastError(0xdeadbeef);
1458 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1459 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1460 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1461 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1462
1463 /* test LCMAP_LOWERCASE */
1464 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1465 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1466 ok(ret == lstrlenW(upper_case) + 1,
1467 "ret %d, error %d, expected value %d\n",
1468 ret, GetLastError(), lstrlenW(upper_case) + 1);
1469 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1470
1471 /* test LCMAP_UPPERCASE */
1472 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1473 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1474 ok(ret == lstrlenW(lower_case) + 1,
1475 "ret %d, error %d, expected value %d\n",
1476 ret, GetLastError(), lstrlenW(lower_case) + 1);
1477 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1478
1479 /* test buffer overflow */
1480 SetLastError(0xdeadbeef);
1481 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1482 lower_case, -1, buf, 4);
1483 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1484 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1485
1486 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1487 lstrcpyW(buf, lower_case);
1488 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1489 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1490 ok(ret == lstrlenW(lower_case) + 1,
1491 "ret %d, error %d, expected value %d\n",
1492 ret, GetLastError(), lstrlenW(lower_case) + 1);
1493 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1494
1495 lstrcpyW(buf, upper_case);
1496 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1497 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1498 ok(ret == lstrlenW(upper_case) + 1,
1499 "ret %d, error %d, expected value %d\n",
1500 ret, GetLastError(), lstrlenW(lower_case) + 1);
1501 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1502
1503 /* otherwise src == dst should fail */
1504 SetLastError(0xdeadbeef);
1505 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1506 buf, 10, buf, sizeof(buf));
1507 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1508 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1509 "unexpected error code %d\n", GetLastError());
1510 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1511
1512 /* test whether '\0' is always appended */
1513 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1514 upper_case, -1, buf, sizeof(buf));
1515 ok(ret, "LCMapStringW must succeed\n");
1516 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1517 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1518 ok(ret, "LCMapStringW must succeed\n");
1519 ok(ret == ret2, "lengths of sort keys must be equal\n");
1520 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1521
1522 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1523 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1524 upper_case, -1, buf, sizeof(buf));
1525 ok(ret, "LCMapStringW must succeed\n");
1526 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1527 lower_case, -1, buf2, sizeof(buf2));
1528 ok(ret2, "LCMapStringW must succeed\n");
1529 ok(ret == ret2, "lengths of sort keys must be equal\n");
1530 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1531
1532 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1533 results from plain LCMAP_SORTKEY on Vista */
1534
1535 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1536 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1537 lower_case, -1, buf, sizeof(buf));
1538 ok(ret, "LCMapStringW must succeed\n");
1539 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1540 symbols_stripped, -1, buf2, sizeof(buf2));
1541 ok(ret2, "LCMapStringW must succeed\n");
1542 ok(ret == ret2, "lengths of sort keys must be equal\n");
1543 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1544
1545 /* test NORM_IGNORENONSPACE */
1546 lstrcpyW(buf, fooW);
1547 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1548 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1549 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1550 lstrlenW(lower_case) + 1, ret);
1551 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1552
1553 /* test NORM_IGNORESYMBOLS */
1554 lstrcpyW(buf, fooW);
1555 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1556 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1557 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1558 lstrlenW(symbols_stripped) + 1, ret);
1559 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1560
1561 /* test srclen = 0 */
1562 SetLastError(0xdeadbeef);
1563 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1564 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1565 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1566 "unexpected error code %d\n", GetLastError());
1567 }
1568
1569 /* this requires collation table patch to make it MS compatible */
1570 static const char * const strings_sorted[] =
1571 {
1572 "'",
1573 "-",
1574 "!",
1575 "\"",
1576 ".",
1577 ":",
1578 "\\",
1579 "_",
1580 "`",
1581 "{",
1582 "}",
1583 "+",
1584 "0",
1585 "1",
1586 "2",
1587 "3",
1588 "4",
1589 "5",
1590 "6",
1591 "7",
1592 "8",
1593 "9",
1594 "a",
1595 "A",
1596 "b",
1597 "B",
1598 "c",
1599 "C"
1600 };
1601
1602 static const char * const strings[] =
1603 {
1604 "C",
1605 "\"",
1606 "9",
1607 "'",
1608 "}",
1609 "-",
1610 "7",
1611 "+",
1612 "`",
1613 "1",
1614 "a",
1615 "5",
1616 "\\",
1617 "8",
1618 "B",
1619 "3",
1620 "_",
1621 "6",
1622 "{",
1623 "2",
1624 "c",
1625 "4",
1626 "!",
1627 "0",
1628 "A",
1629 ":",
1630 "b",
1631 "."
1632 };
1633
1634 static int compare_string1(const void *e1, const void *e2)
1635 {
1636 const char *s1 = *(const char *const *)e1;
1637 const char *s2 = *(const char *const *)e2;
1638
1639 return lstrcmpA(s1, s2);
1640 }
1641
1642 static int compare_string2(const void *e1, const void *e2)
1643 {
1644 const char *s1 = *(const char *const *)e1;
1645 const char *s2 = *(const char *const *)e2;
1646
1647 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1648 }
1649
1650 static int compare_string3(const void *e1, const void *e2)
1651 {
1652 const char *s1 = *(const char *const *)e1;
1653 const char *s2 = *(const char *const *)e2;
1654 char key1[256], key2[256];
1655
1656 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1657 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1658 return strcmp(key1, key2);
1659 }
1660
1661 static void test_sorting(void)
1662 {
1663 char buf[256];
1664 char **str_buf = (char **)buf;
1665 int i;
1666
1667 assert(sizeof(buf) >= sizeof(strings));
1668
1669 /* 1. sort using lstrcmpA */
1670 memcpy(buf, strings, sizeof(strings));
1671 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1672 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1673 {
1674 ok(!strcmp(strings_sorted[i], str_buf[i]),
1675 "qsort using lstrcmpA failed for element %d\n", i);
1676 }
1677 /* 2. sort using CompareStringA */
1678 memcpy(buf, strings, sizeof(strings));
1679 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1680 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1681 {
1682 ok(!strcmp(strings_sorted[i], str_buf[i]),
1683 "qsort using CompareStringA failed for element %d\n", i);
1684 }
1685 /* 3. sort using sort keys */
1686 memcpy(buf, strings, sizeof(strings));
1687 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1688 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1689 {
1690 ok(!strcmp(strings_sorted[i], str_buf[i]),
1691 "qsort using sort keys failed for element %d\n", i);
1692 }
1693 }
1694
1695 static void test_FoldStringA(void)
1696 {
1697 int ret, i, j;
1698 BOOL is_special;
1699 char src[256], dst[256];
1700 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1701 static const char digits_dst[] = { '1','2','3','\0' };
1702 static const char composite_src[] =
1703 {
1704 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1705 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1706 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1707 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1708 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1709 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1710 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1711 0xfb,0xfc,0xfd,0xff,'\0'
1712 };
1713 static const char composite_dst[] =
1714 {
1715 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1716 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1717 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1718 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1719 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1720 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1721 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1722 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1723 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1724 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1725 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1726 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1727 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1728 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1729 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1730 };
1731 static const char composite_dst_alt[] =
1732 {
1733 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1734 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1735 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1736 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1737 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1738 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1739 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1740 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1741 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1742 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1743 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1744 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1745 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1746 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1747 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1748 };
1749 static const char ligatures_src[] =
1750 {
1751 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1752 };
1753 static const char ligatures_dst[] =
1754 {
1755 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1756 };
1757 static const struct special
1758 {
1759 char src;
1760 char dst[4];
1761 } foldczone_special[] =
1762 {
1763 /* src dst */
1764 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1765 { 0x98, { 0x20, 0x7e, 0x00 } },
1766 { 0x99, { 0x54, 0x4d, 0x00 } },
1767 { 0xa0, { 0x20, 0x00 } },
1768 { 0xa8, { 0x20, 0xa8, 0x00 } },
1769 { 0xaa, { 0x61, 0x00 } },
1770 { 0xaf, { 0x20, 0xaf, 0x00 } },
1771 { 0xb2, { 0x32, 0x00 } },
1772 { 0xb3, { 0x33, 0x00 } },
1773 { 0xb4, { 0x20, 0xb4, 0x00 } },
1774 { 0xb8, { 0x20, 0xb8, 0x00 } },
1775 { 0xb9, { 0x31, 0x00 } },
1776 { 0xba, { 0x6f, 0x00 } },
1777 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1778 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1779 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1780 { 0x00 }
1781 };
1782
1783 if (!pFoldStringA)
1784 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1785
1786 /* these tests are locale specific */
1787 if (GetACP() != 1252)
1788 {
1789 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1790 return;
1791 }
1792
1793 /* MAP_FOLDDIGITS */
1794 SetLastError(0);
1795 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1796 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1797 {
1798 win_skip("FoldStringA is not implemented\n");
1799 return;
1800 }
1801 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1802 ok(strcmp(dst, digits_dst) == 0,
1803 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1804 for (i = 1; i < 256; i++)
1805 {
1806 if (!strchr(digits_src, i))
1807 {
1808 src[0] = i;
1809 src[1] = '\0';
1810 SetLastError(0);
1811 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1812 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1813 ok(dst[0] == src[0],
1814 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1815 }
1816 }
1817
1818 /* MAP_EXPAND_LIGATURES */
1819 SetLastError(0);
1820 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1821 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1822 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1823 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1824 ok(strcmp(dst, ligatures_dst) == 0,
1825 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1826 for (i = 1; i < 256; i++)
1827 {
1828 if (!strchr(ligatures_src, i))
1829 {
1830 src[0] = i;
1831 src[1] = '\0';
1832 SetLastError(0);
1833 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1834 if (ret == 3)
1835 {
1836 /* Vista */
1837 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1838 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1839 "Got %s for %d\n", dst, i);
1840 }
1841 else
1842 {
1843 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1844 ok(dst[0] == src[0],
1845 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1846 }
1847 }
1848 }
1849 }
1850
1851 /* MAP_COMPOSITE */
1852 SetLastError(0);
1853 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1854 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1855 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1856 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1857 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1858
1859 for (i = 1; i < 256; i++)
1860 {
1861 if (!strchr(composite_src, i))
1862 {
1863 src[0] = i;
1864 src[1] = '\0';
1865 SetLastError(0);
1866 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1867 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1868 ok(dst[0] == src[0],
1869 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1870 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1871 }
1872 }
1873
1874 /* MAP_FOLDCZONE */
1875 for (i = 1; i < 256; i++)
1876 {
1877 src[0] = i;
1878 src[1] = '\0';
1879 SetLastError(0);
1880 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1881 is_special = FALSE;
1882 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1883 {
1884 if (foldczone_special[j].src == src[0])
1885 {
1886 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1887 "Expected ret == 2 or %d, got %d, error %d\n",
1888 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
1889 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
1890 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
1891 (unsigned char)src[0]);
1892 is_special = TRUE;
1893 }
1894 }
1895 if (! is_special)
1896 {
1897 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1898 ok(src[0] == dst[0],
1899 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1900 (unsigned char)src[0], (unsigned char)dst[0]);
1901 }
1902 }
1903
1904 /* MAP_PRECOMPOSED */
1905 for (i = 1; i < 256; i++)
1906 {
1907 src[0] = i;
1908 src[1] = '\0';
1909 SetLastError(0);
1910 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1911 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1912 ok(src[0] == dst[0],
1913 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1914 (unsigned char)src[0], (unsigned char)dst[0]);
1915 }
1916 }
1917
1918 static void test_FoldStringW(void)
1919 {
1920 int ret;
1921 unsigned int i, j;
1922 WCHAR src[256], dst[256], ch, prev_ch = 1;
1923 static const DWORD badFlags[] =
1924 {
1925 0,
1926 MAP_PRECOMPOSED|MAP_COMPOSITE,
1927 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1928 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
1929 };
1930 /* Ranges of digits 0-9 : Must be sorted! */
1931 static const WCHAR digitRanges[] =
1932 {
1933 0x0030, /* '0'-'9' */
1934 0x0660, /* Eastern Arabic */
1935 0x06F0, /* Arabic - Hindu */
1936 0x0966, /* Devengari */
1937 0x09E6, /* Bengalii */
1938 0x0A66, /* Gurmukhi */
1939 0x0AE6, /* Gujarati */
1940 0x0B66, /* Oriya */
1941 0x0BE6, /* Tamil - No 0 */
1942 0x0C66, /* Telugu */
1943 0x0CE6, /* Kannada */
1944 0x0D66, /* Maylayalam */
1945 0x0E50, /* Thai */
1946 0x0ED0, /* Laos */
1947 0x0F29, /* Tibet - 0 is out of sequence */
1948 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
1949 0x2080, /* Subscript */
1950 0x245F, /* Circled - 0 is out of sequence */
1951 0x2473, /* Bracketed */
1952 0x2487, /* Full stop */
1953 0x2775, /* Inverted circled - No 0 */
1954 0x277F, /* Patterned circled - No 0 */
1955 0x2789, /* Inverted Patterned circled - No 0 */
1956 0x3020, /* Hangzhou */
1957 0xff10, /* Pliene chasse (?) */
1958 0xffff /* Terminator */
1959 };
1960 /* Digits which are represented, but out of sequence */
1961 static const WCHAR outOfSequenceDigits[] =
1962 {
1963 0xB9, /* Superscript 1 */
1964 0xB2, /* Superscript 2 */
1965 0xB3, /* Superscript 3 */
1966 0x0F33, /* Tibetan half zero */
1967 0x24EA, /* Circled 0 */
1968 0x3007, /* Ideographic number zero */
1969 '\0' /* Terminator */
1970 };
1971 /* Digits in digitRanges for which no representation is available */
1972 static const WCHAR noDigitAvailable[] =
1973 {
1974 0x0BE6, /* No Tamil 0 */
1975 0x0F29, /* No Tibetan half zero (out of sequence) */
1976 0x2473, /* No Bracketed 0 */
1977 0x2487, /* No 0 Full stop */
1978 0x2775, /* No inverted circled 0 */
1979 0x277F, /* No patterned circled */
1980 0x2789, /* No inverted Patterned circled */
1981 0x3020, /* No Hangzhou 0 */
1982 '\0' /* Terminator */
1983 };
1984 static const WCHAR foldczone_src[] =
1985 {
1986 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
1987 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
1988 };
1989 static const WCHAR foldczone_dst[] =
1990 {
1991 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
1992 };
1993 static const WCHAR ligatures_src[] =
1994 {
1995 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
1996 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
1997 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
1998 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
1999 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2000 0xfb04, 0xfb05, 0xfb06, '\0'
2001 };
2002 static const WCHAR ligatures_dst[] =
2003 {
2004 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2005 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2006 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2007 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2008 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2009 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2010 };
2011
2012 if (!pFoldStringW)
2013 {
2014 win_skip("FoldStringW is not available\n");
2015 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2016 }
2017
2018 /* Invalid flag combinations */
2019 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2020 {
2021 src[0] = dst[0] = '\0';
2022 SetLastError(0);
2023 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2024 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2025 {
2026 win_skip("FoldStringW is not implemented\n");
2027 return;
2028 }
2029 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2030 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2031 }
2032
2033 /* src & dst cannot be the same */
2034 SetLastError(0);
2035 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2036 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2037 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2038
2039 /* src can't be NULL */
2040 SetLastError(0);
2041 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2042 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2043 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2044
2045 /* srclen can't be 0 */
2046 SetLastError(0);
2047 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2048 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2049 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2050
2051 /* dstlen can't be < 0 */
2052 SetLastError(0);
2053 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2054 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2055 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2056
2057 /* Ret includes terminating NUL which is appended if srclen = -1 */
2058 SetLastError(0);
2059 src[0] = 'A';
2060 src[1] = '\0';
2061 dst[0] = '\0';
2062 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2063 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2064 ok(dst[0] == 'A' && dst[1] == '\0',
2065 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2066 'A', '\0', ret, dst[0], dst[1], GetLastError());
2067
2068 /* If size is given, result is not NUL terminated */
2069 SetLastError(0);
2070 src[0] = 'A';
2071 src[1] = 'A';
2072 dst[0] = 'X';
2073 dst[1] = 'X';
2074 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2075 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2076 ok(dst[0] == 'A' && dst[1] == 'X',
2077 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2078 'A','X', ret, dst[0], dst[1], GetLastError());
2079
2080 /* MAP_FOLDDIGITS */
2081 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2082 {
2083 /* Check everything before this range */
2084 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2085 {
2086 SetLastError(0);
2087 src[0] = ch;
2088 src[1] = dst[0] = '\0';
2089 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2090 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2091
2092 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2093 /* Wine (correctly) maps all Unicode 4.0+ digits */
2094 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
2095 (ch >= 0x1369 && ch <= 0x1371),
2096 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2097 }
2098
2099 if (digitRanges[j] == 0xffff)
2100 break; /* Finished the whole code point space */
2101
2102 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2103 {
2104 WCHAR c;
2105
2106 /* Map out of sequence characters */
2107 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2108 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2109 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2110 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2111 else c = ch;
2112 SetLastError(0);
2113 src[0] = c;
2114 src[1] = dst[0] = '\0';
2115 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2116 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2117
2118 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2119 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2120 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2121 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2122 strchrW(noDigitAvailable, c),
2123 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2124 ch, '0' + digitRanges[j] - ch, dst[0]);
2125 }
2126 prev_ch = ch;
2127 }
2128
2129 /* MAP_FOLDCZONE */
2130 SetLastError(0);
2131 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2132 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2133 "Got %d, error %d\n", ret, GetLastError());
2134 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2135 "MAP_FOLDCZONE: Expanded incorrectly\n");
2136
2137 /* MAP_EXPAND_LIGATURES */
2138 SetLastError(0);
2139 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2140 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2141 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2142 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2143 "Got %d, error %d\n", ret, GetLastError());
2144 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2145 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2146 }
2147
2148 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2149 }
2150
2151
2152
2153 #define LCID_OK(l) \
2154 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2155 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2156 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2157 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2158 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2159
2160 static void test_ConvertDefaultLocale(void)
2161 {
2162 LCID lcid;
2163
2164 /* Doesn't change lcid, even if non default sublang/sort used */
2165 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2166 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2167 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2168 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2169
2170 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2171 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2172 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2173 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2174 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2175
2176 /* Invariant language is not treated specially */
2177 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2178
2179 /* User/system default languages alone are not mapped */
2180 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2181 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2182
2183 /* Default lcids */
2184 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2185 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2186 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2187 }
2188
2189 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2190 DWORD dwFlags, LONG_PTR lParam)
2191 {
2192 trace("%08x, %s, %s, %08x, %08lx\n",
2193 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2194
2195 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2196 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2197
2198 /* If lParam is one, we are calling with flags defaulted from 0 */
2199 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2200 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2201
2202 return TRUE;
2203 }
2204
2205 static void test_EnumSystemLanguageGroupsA(void)
2206 {
2207 BOOL ret;
2208
2209 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2210 {
2211 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2212 return;
2213 }
2214
2215 /* No enumeration proc */
2216 SetLastError(0);
2217 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2218 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2219 {
2220 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2221 return;
2222 }
2223 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2224 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2225
2226 /* Invalid flags */
2227 SetLastError(0);
2228 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2229 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2230
2231 /* No flags - defaults to LGRPID_INSTALLED */
2232 SetLastError(0xdeadbeef);
2233 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2234 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2235
2236 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2237 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2238 }
2239
2240
2241 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2242 LONG_PTR lParam)
2243 {
2244 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2245
2246 /* invalid locale enumerated on some platforms */
2247 if (lcid == 0)
2248 return TRUE;
2249
2250 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2251 "Enumerated grp %d not valid\n", lgrpid);
2252 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2253 "Enumerated grp locale %d not valid\n", lcid);
2254 return TRUE;
2255 }
2256
2257 static void test_EnumLanguageGroupLocalesA(void)
2258 {
2259 BOOL ret;
2260
2261 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2262 {
2263 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2264 return;
2265 }
2266
2267 /* No enumeration proc */
2268 SetLastError(0);
2269 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2270 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2271 {
2272 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2273 return;
2274 }
2275 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2276 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2277
2278 /* lgrpid too small */
2279 SetLastError(0);
2280 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2281 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2282 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2283
2284 /* lgrpid too big */
2285 SetLastError(0);
2286 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2287 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2288 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2289
2290 /* dwFlags is reserved */
2291 SetLastError(0);
2292 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2293 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2294 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2295
2296 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2297 }
2298
2299 static void test_SetLocaleInfoA(void)
2300 {
2301 BOOL bRet;
2302 LCID lcid = GetUserDefaultLCID();
2303
2304 /* Null data */
2305 SetLastError(0);
2306 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2307 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2308 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2309
2310 /* IDATE */
2311 SetLastError(0);
2312 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2313 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2314 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2315
2316 /* ILDATE */
2317 SetLastError(0);
2318 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2319 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2320 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2321 }
2322
2323 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2324 {
2325 trace("%s %08lx\n", value, lParam);
2326 return(TRUE);
2327 }
2328
2329 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2330 {
2331 ok(!enumCount, "callback called again unexpected\n");
2332 enumCount++;
2333 return(FALSE);
2334 }
2335
2336 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2337 {
2338 ok(0,"callback called unexpected\n");
2339 return(FALSE);
2340 }
2341
2342 static void test_EnumUILanguageA(void)
2343 {
2344 BOOL ret;
2345 if (!pEnumUILanguagesA) {
2346 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2347 return;
2348 }
2349
2350 SetLastError(ERROR_SUCCESS);
2351 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2352 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2353 {
2354 win_skip("EnumUILanguagesA is not implemented\n");
2355 return;
2356 }
2357 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2358
2359 enumCount = 0;
2360 SetLastError(ERROR_SUCCESS);
2361 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2362 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2363
2364 SetLastError(ERROR_SUCCESS);
2365 ret = pEnumUILanguagesA(NULL, 0, 0);
2366 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2367 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2368 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2369
2370 SetLastError(ERROR_SUCCESS);
2371 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2372 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2373 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2374
2375 SetLastError(ERROR_SUCCESS);
2376 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2377 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2378 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2379 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2380 }
2381
2382 static char date_fmt_buf[1024];
2383
2384 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2385 {
2386 lstrcatA(date_fmt_buf, fmt);
2387 lstrcatA(date_fmt_buf, "\n");
2388 return TRUE;
2389 }
2390
2391 static void test_EnumDateFormatsA(void)
2392 {
2393 char *p, buf[256];
2394 BOOL ret;
2395 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2396
2397 trace("EnumDateFormatsA 0\n");
2398 date_fmt_buf[0] = 0;
2399 SetLastError(0xdeadbeef);
2400 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2401 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2402 {
2403 win_skip("0 for dwFlags is not supported\n");
2404 }
2405 else
2406 {
2407 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2408 trace("%s\n", date_fmt_buf);
2409 /* test the 1st enumerated format */
2410 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2411 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2412 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2413 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2414 }
2415
2416 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2417 date_fmt_buf[0] = 0;
2418 SetLastError(0xdeadbeef);
2419 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2420 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2421 {
2422 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2423 }
2424 else
2425 {
2426 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2427 trace("%s\n", date_fmt_buf);
2428 /* test the 1st enumerated format */
2429 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2430 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2431 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2432 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2433 }
2434
2435 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2436 date_fmt_buf[0] = 0;
2437 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2438 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2439 trace("%s\n", date_fmt_buf);
2440 /* test the 1st enumerated format */
2441 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2442 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2443 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2444 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2445
2446 trace("EnumDateFormatsA DATE_LONGDATE\n");
2447 date_fmt_buf[0] = 0;
2448 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2449 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2450 trace("%s\n", date_fmt_buf);
2451 /* test the 1st enumerated format */
2452 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2453 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2454 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2455 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2456
2457 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2458 date_fmt_buf[0] = 0;
2459 SetLastError(0xdeadbeef);
2460 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2461 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2462 {
2463 skip("DATE_YEARMONTH is only present on W2K and later\n");
2464 return;
2465 }
2466 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2467 trace("%s\n", date_fmt_buf);
2468 /* test the 1st enumerated format */
2469 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2470 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2471 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2472 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2473 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2474 }
2475
2476 static void test_EnumTimeFormatsA(void)
2477 {
2478 char *p, buf[256];
2479 BOOL ret;
2480 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2481
2482 trace("EnumTimeFormatsA 0\n");
2483 date_fmt_buf[0] = 0;
2484 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2485 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2486 trace("%s\n", date_fmt_buf);
2487 /* test the 1st enumerated format */
2488 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2489 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2490 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2491 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2492
2493 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2494 date_fmt_buf[0] = 0;
2495 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2496 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2497 trace("%s\n", date_fmt_buf);
2498 /* test the 1st enumerated format */
2499 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2500 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2501 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2502 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2503 }
2504
2505 static void test_GetCPInfo(void)
2506 {
2507 BOOL ret;
2508 CPINFO cpinfo;
2509
2510 SetLastError(0xdeadbeef);
2511 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2512 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2513 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2514 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2515
2516 SetLastError(0xdeadbeef);
2517 ret = GetCPInfo(CP_UTF7, &cpinfo);
2518 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2519 {
2520 skip("Codepage CP_UTF7 is not installed/available\n");
2521 }
2522 else
2523 {
2524 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2525 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2526 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2527 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2528 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2529 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2530 }
2531
2532 SetLastError(0xdeadbeef);
2533 ret = GetCPInfo(CP_UTF8, &cpinfo);
2534 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2535 {
2536 skip("Codepage CP_UTF8 is not installed/available\n");
2537 }
2538 else
2539 {
2540 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2541 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2542 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2543 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2544 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2545 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2546 "expected 4, got %u\n", cpinfo.MaxCharSize);
2547 }
2548 }
2549
2550 START_TEST(locale)
2551 {
2552 InitFunctionPointers();
2553
2554 test_EnumTimeFormatsA();
2555 test_EnumDateFormatsA();
2556 test_GetLocaleInfoA();
2557 test_GetLocaleInfoW();
2558 test_GetTimeFormatA();
2559 test_GetDateFormatA();
2560 test_GetDateFormatW();
2561 test_GetCurrencyFormatA(); /* Also tests the W version */
2562 test_GetNumberFormatA(); /* Also tests the W version */
2563 test_CompareStringA();
2564 test_LCMapStringA();
2565 test_LCMapStringW();
2566 test_FoldStringA();
2567 test_FoldStringW();
2568 test_ConvertDefaultLocale();
2569 test_EnumSystemLanguageGroupsA();
2570 test_EnumLanguageGroupLocalesA();
2571 test_SetLocaleInfoA();
2572 test_EnumUILanguageA();
2573 test_GetCPInfo();
2574 /* this requires collation table patch to make it MS compatible */
2575 if (0) test_sorting();
2576 }