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