Merge trunk head (46467)
[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 = lstrcmpi("#", ".");
1351 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1352 }
1353
1354 static void test_LCMapStringA(void)
1355 {
1356 int ret, ret2;
1357 char buf[256], buf2[256];
1358 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1359 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1360 static const char symbols_stripped[] = "justateststring1";
1361
1362 SetLastError(0xdeadbeef);
1363 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1364 lower_case, -1, buf, sizeof(buf));
1365 ok(ret == lstrlenA(lower_case) + 1,
1366 "ret %d, error %d, expected value %d\n",
1367 ret, GetLastError(), lstrlenA(lower_case) + 1);
1368 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1369
1370 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1371 upper_case, -1, buf, sizeof(buf));
1372 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1373 ok(GetLastError() == ERROR_INVALID_FLAGS,
1374 "unexpected error code %d\n", GetLastError());
1375
1376 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1377 upper_case, -1, buf, sizeof(buf));
1378 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1379 ok(GetLastError() == ERROR_INVALID_FLAGS,
1380 "unexpected error code %d\n", GetLastError());
1381
1382 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1383 upper_case, -1, buf, sizeof(buf));
1384 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1385 ok(GetLastError() == ERROR_INVALID_FLAGS,
1386 "unexpected error code %d\n", GetLastError());
1387
1388 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1389 upper_case, -1, buf, sizeof(buf));
1390 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1391 ok(GetLastError() == ERROR_INVALID_FLAGS,
1392 "unexpected error code %d\n", GetLastError());
1393
1394 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1395 SetLastError(0xdeadbeef);
1396 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1397 upper_case, -1, buf, sizeof(buf));
1398 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1399 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1400
1401 /* test LCMAP_LOWERCASE */
1402 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1403 upper_case, -1, buf, sizeof(buf));
1404 ok(ret == lstrlenA(upper_case) + 1,
1405 "ret %d, error %d, expected value %d\n",
1406 ret, GetLastError(), lstrlenA(upper_case) + 1);
1407 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1408
1409 /* test LCMAP_UPPERCASE */
1410 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1411 lower_case, -1, buf, sizeof(buf));
1412 ok(ret == lstrlenA(lower_case) + 1,
1413 "ret %d, error %d, expected value %d\n",
1414 ret, GetLastError(), lstrlenA(lower_case) + 1);
1415 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1416
1417 /* test buffer overflow */
1418 SetLastError(0xdeadbeef);
1419 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1420 lower_case, -1, buf, 4);
1421 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1422 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1423
1424 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1425 lstrcpyA(buf, lower_case);
1426 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1427 buf, -1, buf, sizeof(buf));
1428 if (!ret) /* Win9x */
1429 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1430 else
1431 {
1432 ok(ret == lstrlenA(lower_case) + 1,
1433 "ret %d, error %d, expected value %d\n",
1434 ret, GetLastError(), lstrlenA(lower_case) + 1);
1435 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1436 }
1437 lstrcpyA(buf, upper_case);
1438 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1439 buf, -1, buf, sizeof(buf));
1440 if (!ret) /* Win9x */
1441 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1442 else
1443 {
1444 ok(ret == lstrlenA(upper_case) + 1,
1445 "ret %d, error %d, expected value %d\n",
1446 ret, GetLastError(), lstrlenA(lower_case) + 1);
1447 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1448 }
1449
1450 /* otherwise src == dst should fail */
1451 SetLastError(0xdeadbeef);
1452 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1453 buf, 10, buf, sizeof(buf));
1454 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1455 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1456 "unexpected error code %d\n", GetLastError());
1457 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1458
1459 /* test whether '\0' is always appended */
1460 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1461 upper_case, -1, buf, sizeof(buf));
1462 ok(ret, "LCMapStringA must succeed\n");
1463 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1464 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1465 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1466 ok(ret2, "LCMapStringA must succeed\n");
1467 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1468 ok(ret == ret2, "lengths of sort keys must be equal\n");
1469 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1470
1471 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1472 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1473 upper_case, -1, buf, sizeof(buf));
1474 ok(ret, "LCMapStringA must succeed\n");
1475 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1476 lower_case, -1, buf2, sizeof(buf2));
1477 ok(ret2, "LCMapStringA must succeed\n");
1478 ok(ret == ret2, "lengths of sort keys must be equal\n");
1479 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1480
1481 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1482 results from plain LCMAP_SORTKEY on Vista */
1483
1484 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1485 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1486 lower_case, -1, buf, sizeof(buf));
1487 ok(ret, "LCMapStringA must succeed\n");
1488 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1489 symbols_stripped, -1, buf2, sizeof(buf2));
1490 ok(ret2, "LCMapStringA must succeed\n");
1491 ok(ret == ret2, "lengths of sort keys must be equal\n");
1492 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1493
1494 /* test NORM_IGNORENONSPACE */
1495 lstrcpyA(buf, "foo");
1496 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1497 lower_case, -1, buf, sizeof(buf));
1498 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1499 lstrlenA(lower_case) + 1, ret);
1500 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1501
1502 /* test NORM_IGNORESYMBOLS */
1503 lstrcpyA(buf, "foo");
1504 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1505 lower_case, -1, buf, sizeof(buf));
1506 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1507 lstrlenA(symbols_stripped) + 1, ret);
1508 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1509
1510 /* test srclen = 0 */
1511 SetLastError(0xdeadbeef);
1512 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1513 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1514 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1515 "unexpected error code %d\n", GetLastError());
1516 }
1517
1518 static void test_LCMapStringW(void)
1519 {
1520 int ret, ret2;
1521 WCHAR buf[256], buf2[256];
1522 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1523 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};
1524 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};
1525 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1526 static const WCHAR fooW[] = {'f','o','o',0};
1527
1528 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1529 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1530 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1531 {
1532 win_skip("LCMapStringW is not implemented\n");
1533 return;
1534 }
1535 if (broken(ret))
1536 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1537 else
1538 {
1539 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1540 ok(GetLastError() == ERROR_INVALID_FLAGS,
1541 "unexpected error code %d\n", GetLastError());
1542 }
1543
1544 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1545 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1546 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1547 ok(GetLastError() == ERROR_INVALID_FLAGS,
1548 "unexpected error code %d\n", GetLastError());
1549
1550 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1551 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1552 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1553 ok(GetLastError() == ERROR_INVALID_FLAGS,
1554 "unexpected error code %d\n", GetLastError());
1555
1556 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1557 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1558 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1559 ok(GetLastError() == ERROR_INVALID_FLAGS,
1560 "unexpected error code %d\n", GetLastError());
1561
1562 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1563 SetLastError(0xdeadbeef);
1564 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1565 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1566 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1567 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1568
1569 /* test LCMAP_LOWERCASE */
1570 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1571 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1572 ok(ret == lstrlenW(upper_case) + 1,
1573 "ret %d, error %d, expected value %d\n",
1574 ret, GetLastError(), lstrlenW(upper_case) + 1);
1575 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1576
1577 /* test LCMAP_UPPERCASE */
1578 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1579 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1580 ok(ret == lstrlenW(lower_case) + 1,
1581 "ret %d, error %d, expected value %d\n",
1582 ret, GetLastError(), lstrlenW(lower_case) + 1);
1583 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1584
1585 /* test buffer overflow */
1586 SetLastError(0xdeadbeef);
1587 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1588 lower_case, -1, buf, 4);
1589 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1590 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1591
1592 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1593 lstrcpyW(buf, lower_case);
1594 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1595 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1596 ok(ret == lstrlenW(lower_case) + 1,
1597 "ret %d, error %d, expected value %d\n",
1598 ret, GetLastError(), lstrlenW(lower_case) + 1);
1599 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1600
1601 lstrcpyW(buf, upper_case);
1602 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1603 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1604 ok(ret == lstrlenW(upper_case) + 1,
1605 "ret %d, error %d, expected value %d\n",
1606 ret, GetLastError(), lstrlenW(lower_case) + 1);
1607 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1608
1609 /* otherwise src == dst should fail */
1610 SetLastError(0xdeadbeef);
1611 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1612 buf, 10, buf, sizeof(buf));
1613 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1614 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1615 "unexpected error code %d\n", GetLastError());
1616 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1617
1618 /* test whether '\0' is always appended */
1619 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1620 upper_case, -1, buf, sizeof(buf));
1621 ok(ret, "LCMapStringW must succeed\n");
1622 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1623 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1624 ok(ret, "LCMapStringW must succeed\n");
1625 ok(ret == ret2, "lengths of sort keys must be equal\n");
1626 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1627
1628 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1629 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1630 upper_case, -1, buf, sizeof(buf));
1631 ok(ret, "LCMapStringW must succeed\n");
1632 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1633 lower_case, -1, buf2, sizeof(buf2));
1634 ok(ret2, "LCMapStringW must succeed\n");
1635 ok(ret == ret2, "lengths of sort keys must be equal\n");
1636 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1637
1638 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1639 results from plain LCMAP_SORTKEY on Vista */
1640
1641 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1642 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1643 lower_case, -1, buf, sizeof(buf));
1644 ok(ret, "LCMapStringW must succeed\n");
1645 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1646 symbols_stripped, -1, buf2, sizeof(buf2));
1647 ok(ret2, "LCMapStringW must succeed\n");
1648 ok(ret == ret2, "lengths of sort keys must be equal\n");
1649 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1650
1651 /* test NORM_IGNORENONSPACE */
1652 lstrcpyW(buf, fooW);
1653 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1654 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1655 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1656 lstrlenW(lower_case) + 1, ret);
1657 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1658
1659 /* test NORM_IGNORESYMBOLS */
1660 lstrcpyW(buf, fooW);
1661 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1662 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1663 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1664 lstrlenW(symbols_stripped) + 1, ret);
1665 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1666
1667 /* test srclen = 0 */
1668 SetLastError(0xdeadbeef);
1669 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1670 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1671 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1672 "unexpected error code %d\n", GetLastError());
1673 }
1674
1675 /* this requires collation table patch to make it MS compatible */
1676 static const char * const strings_sorted[] =
1677 {
1678 "'",
1679 "-",
1680 "!",
1681 "\"",
1682 ".",
1683 ":",
1684 "\\",
1685 "_",
1686 "`",
1687 "{",
1688 "}",
1689 "+",
1690 "0",
1691 "1",
1692 "2",
1693 "3",
1694 "4",
1695 "5",
1696 "6",
1697 "7",
1698 "8",
1699 "9",
1700 "a",
1701 "A",
1702 "b",
1703 "B",
1704 "c",
1705 "C"
1706 };
1707
1708 static const char * const strings[] =
1709 {
1710 "C",
1711 "\"",
1712 "9",
1713 "'",
1714 "}",
1715 "-",
1716 "7",
1717 "+",
1718 "`",
1719 "1",
1720 "a",
1721 "5",
1722 "\\",
1723 "8",
1724 "B",
1725 "3",
1726 "_",
1727 "6",
1728 "{",
1729 "2",
1730 "c",
1731 "4",
1732 "!",
1733 "0",
1734 "A",
1735 ":",
1736 "b",
1737 "."
1738 };
1739
1740 static int compare_string1(const void *e1, const void *e2)
1741 {
1742 const char *s1 = *(const char *const *)e1;
1743 const char *s2 = *(const char *const *)e2;
1744
1745 return lstrcmpA(s1, s2);
1746 }
1747
1748 static int compare_string2(const void *e1, const void *e2)
1749 {
1750 const char *s1 = *(const char *const *)e1;
1751 const char *s2 = *(const char *const *)e2;
1752
1753 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1754 }
1755
1756 static int compare_string3(const void *e1, const void *e2)
1757 {
1758 const char *s1 = *(const char *const *)e1;
1759 const char *s2 = *(const char *const *)e2;
1760 char key1[256], key2[256];
1761
1762 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1763 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1764 return strcmp(key1, key2);
1765 }
1766
1767 static void test_sorting(void)
1768 {
1769 char buf[256];
1770 char **str_buf = (char **)buf;
1771 int i;
1772
1773 assert(sizeof(buf) >= sizeof(strings));
1774
1775 /* 1. sort using lstrcmpA */
1776 memcpy(buf, strings, sizeof(strings));
1777 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1778 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1779 {
1780 ok(!strcmp(strings_sorted[i], str_buf[i]),
1781 "qsort using lstrcmpA failed for element %d\n", i);
1782 }
1783 /* 2. sort using CompareStringA */
1784 memcpy(buf, strings, sizeof(strings));
1785 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1786 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1787 {
1788 ok(!strcmp(strings_sorted[i], str_buf[i]),
1789 "qsort using CompareStringA failed for element %d\n", i);
1790 }
1791 /* 3. sort using sort keys */
1792 memcpy(buf, strings, sizeof(strings));
1793 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1794 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1795 {
1796 ok(!strcmp(strings_sorted[i], str_buf[i]),
1797 "qsort using sort keys failed for element %d\n", i);
1798 }
1799 }
1800
1801 static void test_FoldStringA(void)
1802 {
1803 int ret, i, j;
1804 BOOL is_special;
1805 char src[256], dst[256];
1806 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1807 static const char digits_dst[] = { '1','2','3','\0' };
1808 static const char composite_src[] =
1809 {
1810 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1811 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1812 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1813 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1814 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1815 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1816 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1817 0xfb,0xfc,0xfd,0xff,'\0'
1818 };
1819 static const char composite_dst[] =
1820 {
1821 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1822 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1823 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1824 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1825 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1826 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1827 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1828 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1829 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1830 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1831 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1832 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1833 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1834 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1835 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1836 };
1837 static const char composite_dst_alt[] =
1838 {
1839 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1840 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1841 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1842 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1843 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1844 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1845 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1846 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1847 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1848 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1849 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1850 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1851 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1852 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1853 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1854 };
1855 static const char ligatures_src[] =
1856 {
1857 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1858 };
1859 static const char ligatures_dst[] =
1860 {
1861 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1862 };
1863 static const struct special
1864 {
1865 char src;
1866 char dst[4];
1867 } foldczone_special[] =
1868 {
1869 /* src dst */
1870 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1871 { 0x98, { 0x20, 0x7e, 0x00 } },
1872 { 0x99, { 0x54, 0x4d, 0x00 } },
1873 { 0xa0, { 0x20, 0x00 } },
1874 { 0xa8, { 0x20, 0xa8, 0x00 } },
1875 { 0xaa, { 0x61, 0x00 } },
1876 { 0xaf, { 0x20, 0xaf, 0x00 } },
1877 { 0xb2, { 0x32, 0x00 } },
1878 { 0xb3, { 0x33, 0x00 } },
1879 { 0xb4, { 0x20, 0xb4, 0x00 } },
1880 { 0xb8, { 0x20, 0xb8, 0x00 } },
1881 { 0xb9, { 0x31, 0x00 } },
1882 { 0xba, { 0x6f, 0x00 } },
1883 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1884 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1885 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1886 { 0x00 }
1887 };
1888
1889 if (!pFoldStringA)
1890 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1891
1892 /* these tests are locale specific */
1893 if (GetACP() != 1252)
1894 {
1895 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1896 return;
1897 }
1898
1899 /* MAP_FOLDDIGITS */
1900 SetLastError(0);
1901 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1902 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
1903 {
1904 win_skip("FoldStringA is not implemented\n");
1905 return;
1906 }
1907 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1908 ok(strcmp(dst, digits_dst) == 0,
1909 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1910 for (i = 1; i < 256; i++)
1911 {
1912 if (!strchr(digits_src, i))
1913 {
1914 src[0] = i;
1915 src[1] = '\0';
1916 SetLastError(0);
1917 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1918 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1919 ok(dst[0] == src[0],
1920 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1921 }
1922 }
1923
1924 /* MAP_EXPAND_LIGATURES */
1925 SetLastError(0);
1926 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1927 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1928 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1929 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1930 ok(strcmp(dst, ligatures_dst) == 0,
1931 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1932 for (i = 1; i < 256; i++)
1933 {
1934 if (!strchr(ligatures_src, i))
1935 {
1936 src[0] = i;
1937 src[1] = '\0';
1938 SetLastError(0);
1939 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1940 if (ret == 3)
1941 {
1942 /* Vista */
1943 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1944 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1945 "Got %s for %d\n", dst, i);
1946 }
1947 else
1948 {
1949 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1950 ok(dst[0] == src[0],
1951 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1952 }
1953 }
1954 }
1955 }
1956
1957 /* MAP_COMPOSITE */
1958 SetLastError(0);
1959 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1960 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1961 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1962 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1963 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1964
1965 for (i = 1; i < 256; i++)
1966 {
1967 if (!strchr(composite_src, i))
1968 {
1969 src[0] = i;
1970 src[1] = '\0';
1971 SetLastError(0);
1972 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1973 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1974 ok(dst[0] == src[0],
1975 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1976 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1977 }
1978 }
1979
1980 /* MAP_FOLDCZONE */
1981 for (i = 1; i < 256; i++)
1982 {
1983 src[0] = i;
1984 src[1] = '\0';
1985 SetLastError(0);
1986 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1987 is_special = FALSE;
1988 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1989 {
1990 if (foldczone_special[j].src == src[0])
1991 {
1992 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1993 "Expected ret == 2 or %d, got %d, error %d\n",
1994 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
1995 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
1996 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
1997 (unsigned char)src[0]);
1998 is_special = TRUE;
1999 }
2000 }
2001 if (! is_special)
2002 {
2003 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2004 ok(src[0] == dst[0],
2005 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2006 (unsigned char)src[0], (unsigned char)dst[0]);
2007 }
2008 }
2009
2010 /* MAP_PRECOMPOSED */
2011 for (i = 1; i < 256; i++)
2012 {
2013 src[0] = i;
2014 src[1] = '\0';
2015 SetLastError(0);
2016 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2017 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2018 ok(src[0] == dst[0],
2019 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2020 (unsigned char)src[0], (unsigned char)dst[0]);
2021 }
2022 }
2023
2024 static void test_FoldStringW(void)
2025 {
2026 int ret;
2027 unsigned int i, j;
2028 WCHAR src[256], dst[256], ch, prev_ch = 1;
2029 static const DWORD badFlags[] =
2030 {
2031 0,
2032 MAP_PRECOMPOSED|MAP_COMPOSITE,
2033 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2034 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2035 };
2036 /* Ranges of digits 0-9 : Must be sorted! */
2037 static const WCHAR digitRanges[] =
2038 {
2039 0x0030, /* '0'-'9' */
2040 0x0660, /* Eastern Arabic */
2041 0x06F0, /* Arabic - Hindu */
2042 0x0966, /* Devengari */
2043 0x09E6, /* Bengalii */
2044 0x0A66, /* Gurmukhi */
2045 0x0AE6, /* Gujarati */
2046 0x0B66, /* Oriya */
2047 0x0BE6, /* Tamil - No 0 */
2048 0x0C66, /* Telugu */
2049 0x0CE6, /* Kannada */
2050 0x0D66, /* Maylayalam */
2051 0x0E50, /* Thai */
2052 0x0ED0, /* Laos */
2053 0x0F29, /* Tibet - 0 is out of sequence */
2054 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2055 0x2080, /* Subscript */
2056 0x245F, /* Circled - 0 is out of sequence */
2057 0x2473, /* Bracketed */
2058 0x2487, /* Full stop */
2059 0x2775, /* Inverted circled - No 0 */
2060 0x277F, /* Patterned circled - No 0 */
2061 0x2789, /* Inverted Patterned circled - No 0 */
2062 0x3020, /* Hangzhou */
2063 0xff10, /* Pliene chasse (?) */
2064 0xffff /* Terminator */
2065 };
2066 /* Digits which are represented, but out of sequence */
2067 static const WCHAR outOfSequenceDigits[] =
2068 {
2069 0xB9, /* Superscript 1 */
2070 0xB2, /* Superscript 2 */
2071 0xB3, /* Superscript 3 */
2072 0x0F33, /* Tibetan half zero */
2073 0x24EA, /* Circled 0 */
2074 0x3007, /* Ideographic number zero */
2075 '\0' /* Terminator */
2076 };
2077 /* Digits in digitRanges for which no representation is available */
2078 static const WCHAR noDigitAvailable[] =
2079 {
2080 0x0BE6, /* No Tamil 0 */
2081 0x0F29, /* No Tibetan half zero (out of sequence) */
2082 0x2473, /* No Bracketed 0 */
2083 0x2487, /* No 0 Full stop */
2084 0x2775, /* No inverted circled 0 */
2085 0x277F, /* No patterned circled */
2086 0x2789, /* No inverted Patterned circled */
2087 0x3020, /* No Hangzhou 0 */
2088 '\0' /* Terminator */
2089 };
2090 static const WCHAR foldczone_src[] =
2091 {
2092 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2093 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2094 };
2095 static const WCHAR foldczone_dst[] =
2096 {
2097 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2098 };
2099 static const WCHAR ligatures_src[] =
2100 {
2101 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2102 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2103 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2104 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2105 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2106 0xfb04, 0xfb05, 0xfb06, '\0'
2107 };
2108 static const WCHAR ligatures_dst[] =
2109 {
2110 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2111 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2112 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2113 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2114 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2115 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2116 };
2117
2118 if (!pFoldStringW)
2119 {
2120 win_skip("FoldStringW is not available\n");
2121 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2122 }
2123
2124 /* Invalid flag combinations */
2125 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2126 {
2127 src[0] = dst[0] = '\0';
2128 SetLastError(0);
2129 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2130 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2131 {
2132 win_skip("FoldStringW is not implemented\n");
2133 return;
2134 }
2135 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2136 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2137 }
2138
2139 /* src & dst cannot be the same */
2140 SetLastError(0);
2141 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2142 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2143 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2144
2145 /* src can't be NULL */
2146 SetLastError(0);
2147 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2148 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2149 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2150
2151 /* srclen can't be 0 */
2152 SetLastError(0);
2153 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2154 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2155 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2156
2157 /* dstlen can't be < 0 */
2158 SetLastError(0);
2159 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2160 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2161 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2162
2163 /* Ret includes terminating NUL which is appended if srclen = -1 */
2164 SetLastError(0);
2165 src[0] = 'A';
2166 src[1] = '\0';
2167 dst[0] = '\0';
2168 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2169 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2170 ok(dst[0] == 'A' && dst[1] == '\0',
2171 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2172 'A', '\0', ret, dst[0], dst[1], GetLastError());
2173
2174 /* If size is given, result is not NUL terminated */
2175 SetLastError(0);
2176 src[0] = 'A';
2177 src[1] = 'A';
2178 dst[0] = 'X';
2179 dst[1] = 'X';
2180 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2181 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2182 ok(dst[0] == 'A' && dst[1] == 'X',
2183 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2184 'A','X', ret, dst[0], dst[1], GetLastError());
2185
2186 /* MAP_FOLDDIGITS */
2187 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2188 {
2189 /* Check everything before this range */
2190 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2191 {
2192 SetLastError(0);
2193 src[0] = ch;
2194 src[1] = dst[0] = '\0';
2195 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2196 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2197
2198 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2199 /* Wine (correctly) maps all Unicode 4.0+ digits */
2200 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
2201 (ch >= 0x1369 && ch <= 0x1371),
2202 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2203 }
2204
2205 if (digitRanges[j] == 0xffff)
2206 break; /* Finished the whole code point space */
2207
2208 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2209 {
2210 WCHAR c;
2211
2212 /* Map out of sequence characters */
2213 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2214 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2215 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2216 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2217 else c = ch;
2218 SetLastError(0);
2219 src[0] = c;
2220 src[1] = dst[0] = '\0';
2221 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2222 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2223
2224 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2225 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2226 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2227 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2228 strchrW(noDigitAvailable, c),
2229 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2230 ch, '0' + digitRanges[j] - ch, dst[0]);
2231 }
2232 prev_ch = ch;
2233 }
2234
2235 /* MAP_FOLDCZONE */
2236 SetLastError(0);
2237 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2238 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2239 "Got %d, error %d\n", ret, GetLastError());
2240 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2241 "MAP_FOLDCZONE: Expanded incorrectly\n");
2242
2243 /* MAP_EXPAND_LIGATURES */
2244 SetLastError(0);
2245 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2246 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2247 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2248 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2249 "Got %d, error %d\n", ret, GetLastError());
2250 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2251 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2252 }
2253
2254 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2255 }
2256
2257
2258
2259 #define LCID_OK(l) \
2260 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2261 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2262 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2263 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2264 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2265
2266 static void test_ConvertDefaultLocale(void)
2267 {
2268 LCID lcid;
2269
2270 /* Doesn't change lcid, even if non default sublang/sort used */
2271 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2272 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2273 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2274 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2275
2276 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2277 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2278 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2279 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2280 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2281
2282 /* Invariant language is not treated specially */
2283 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2284
2285 /* User/system default languages alone are not mapped */
2286 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2287 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2288
2289 /* Default lcids */
2290 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2291 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2292 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2293 }
2294
2295 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2296 DWORD dwFlags, LONG_PTR lParam)
2297 {
2298 trace("%08x, %s, %s, %08x, %08lx\n",
2299 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2300
2301 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2302 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2303
2304 /* If lParam is one, we are calling with flags defaulted from 0 */
2305 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2306 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2307
2308 return TRUE;
2309 }
2310
2311 static void test_EnumSystemLanguageGroupsA(void)
2312 {
2313 BOOL ret;
2314
2315 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2316 {
2317 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2318 return;
2319 }
2320
2321 /* No enumeration proc */
2322 SetLastError(0);
2323 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2324 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2325 {
2326 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2327 return;
2328 }
2329 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2330 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2331
2332 /* Invalid flags */
2333 SetLastError(0);
2334 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2335 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2336
2337 /* No flags - defaults to LGRPID_INSTALLED */
2338 SetLastError(0xdeadbeef);
2339 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2340 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2341
2342 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2343 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2344 }
2345
2346
2347 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2348 LONG_PTR lParam)
2349 {
2350 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2351
2352 /* invalid locale enumerated on some platforms */
2353 if (lcid == 0)
2354 return TRUE;
2355
2356 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2357 "Enumerated grp %d not valid\n", lgrpid);
2358 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2359 "Enumerated grp locale %d not valid\n", lcid);
2360 return TRUE;
2361 }
2362
2363 static void test_EnumLanguageGroupLocalesA(void)
2364 {
2365 BOOL ret;
2366
2367 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2368 {
2369 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2370 return;
2371 }
2372
2373 /* No enumeration proc */
2374 SetLastError(0);
2375 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2376 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2377 {
2378 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2379 return;
2380 }
2381 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2382 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2383
2384 /* lgrpid too small */
2385 SetLastError(0);
2386 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2387 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2388 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2389
2390 /* lgrpid too big */
2391 SetLastError(0);
2392 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2393 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2394 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2395
2396 /* dwFlags is reserved */
2397 SetLastError(0);
2398 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2399 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2400 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2401
2402 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2403 }
2404
2405 static void test_SetLocaleInfoA(void)
2406 {
2407 BOOL bRet;
2408 LCID lcid = GetUserDefaultLCID();
2409
2410 /* Null data */
2411 SetLastError(0);
2412 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2413 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2414 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2415
2416 /* IDATE */
2417 SetLastError(0);
2418 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
2419 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2420 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2421
2422 /* ILDATE */
2423 SetLastError(0);
2424 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
2425 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2426 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2427 }
2428
2429 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2430 {
2431 trace("%s %08lx\n", value, lParam);
2432 return(TRUE);
2433 }
2434
2435 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2436 {
2437 ok(!enumCount, "callback called again unexpected\n");
2438 enumCount++;
2439 return(FALSE);
2440 }
2441
2442 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2443 {
2444 ok(0,"callback called unexpected\n");
2445 return(FALSE);
2446 }
2447
2448 static void test_EnumUILanguageA(void)
2449 {
2450 BOOL ret;
2451 if (!pEnumUILanguagesA) {
2452 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2453 return;
2454 }
2455
2456 SetLastError(ERROR_SUCCESS);
2457 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2458 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2459 {
2460 win_skip("EnumUILanguagesA is not implemented\n");
2461 return;
2462 }
2463 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2464
2465 enumCount = 0;
2466 SetLastError(ERROR_SUCCESS);
2467 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2468 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2469
2470 SetLastError(ERROR_SUCCESS);
2471 ret = pEnumUILanguagesA(NULL, 0, 0);
2472 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2473 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2474 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2475
2476 SetLastError(ERROR_SUCCESS);
2477 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2478 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2479 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2480
2481 SetLastError(ERROR_SUCCESS);
2482 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2483 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2484 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2485 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2486 }
2487
2488 static char date_fmt_buf[1024];
2489
2490 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2491 {
2492 lstrcatA(date_fmt_buf, fmt);
2493 lstrcatA(date_fmt_buf, "\n");
2494 return TRUE;
2495 }
2496
2497 static void test_EnumDateFormatsA(void)
2498 {
2499 char *p, buf[256];
2500 BOOL ret;
2501 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2502
2503 trace("EnumDateFormatsA 0\n");
2504 date_fmt_buf[0] = 0;
2505 SetLastError(0xdeadbeef);
2506 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2507 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2508 {
2509 win_skip("0 for dwFlags is not supported\n");
2510 }
2511 else
2512 {
2513 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2514 trace("%s\n", date_fmt_buf);
2515 /* test the 1st enumerated format */
2516 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2517 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2518 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2519 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2520 }
2521
2522 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2523 date_fmt_buf[0] = 0;
2524 SetLastError(0xdeadbeef);
2525 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2526 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2527 {
2528 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2529 }
2530 else
2531 {
2532 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2533 trace("%s\n", date_fmt_buf);
2534 /* test the 1st enumerated format */
2535 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2536 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2537 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2538 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2539 }
2540
2541 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2542 date_fmt_buf[0] = 0;
2543 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2544 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2545 trace("%s\n", date_fmt_buf);
2546 /* test the 1st enumerated format */
2547 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2548 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2549 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2550 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2551
2552 trace("EnumDateFormatsA DATE_LONGDATE\n");
2553 date_fmt_buf[0] = 0;
2554 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2555 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2556 trace("%s\n", date_fmt_buf);
2557 /* test the 1st enumerated format */
2558 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2559 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2560 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2561 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2562
2563 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2564 date_fmt_buf[0] = 0;
2565 SetLastError(0xdeadbeef);
2566 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2567 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2568 {
2569 skip("DATE_YEARMONTH is only present on W2K and later\n");
2570 return;
2571 }
2572 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2573 trace("%s\n", date_fmt_buf);
2574 /* test the 1st enumerated format */
2575 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2576 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2577 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2578 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2579 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2580 }
2581
2582 static void test_EnumTimeFormatsA(void)
2583 {
2584 char *p, buf[256];
2585 BOOL ret;
2586 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2587
2588 trace("EnumTimeFormatsA 0\n");
2589 date_fmt_buf[0] = 0;
2590 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2591 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2592 trace("%s\n", date_fmt_buf);
2593 /* test the 1st enumerated format */
2594 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2595 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2596 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2597 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2598
2599 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2600 date_fmt_buf[0] = 0;
2601 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2602 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2603 trace("%s\n", date_fmt_buf);
2604 /* test the 1st enumerated format */
2605 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2606 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2607 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2608 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2609 }
2610
2611 static void test_GetCPInfo(void)
2612 {
2613 BOOL ret;
2614 CPINFO cpinfo;
2615
2616 SetLastError(0xdeadbeef);
2617 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2618 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2619 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2620 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2621
2622 SetLastError(0xdeadbeef);
2623 ret = GetCPInfo(CP_UTF7, &cpinfo);
2624 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2625 {
2626 skip("Codepage CP_UTF7 is not installed/available\n");
2627 }
2628 else
2629 {
2630 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2631 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2632 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2633 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2634 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2635 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2636 }
2637
2638 SetLastError(0xdeadbeef);
2639 ret = GetCPInfo(CP_UTF8, &cpinfo);
2640 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2641 {
2642 skip("Codepage CP_UTF8 is not installed/available\n");
2643 }
2644 else
2645 {
2646 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2647 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2648 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2649 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2650 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2651 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2652 "expected 4, got %u\n", cpinfo.MaxCharSize);
2653 }
2654 }
2655
2656 START_TEST(locale)
2657 {
2658 InitFunctionPointers();
2659
2660 test_EnumTimeFormatsA();
2661 test_EnumDateFormatsA();
2662 test_GetLocaleInfoA();
2663 test_GetLocaleInfoW();
2664 test_GetTimeFormatA();
2665 test_GetDateFormatA();
2666 test_GetDateFormatW();
2667 test_GetCurrencyFormatA(); /* Also tests the W version */
2668 test_GetNumberFormatA(); /* Also tests the W version */
2669 test_CompareStringA();
2670 test_LCMapStringA();
2671 test_LCMapStringW();
2672 test_FoldStringA();
2673 test_FoldStringW();
2674 test_ConvertDefaultLocale();
2675 test_EnumSystemLanguageGroupsA();
2676 test_EnumLanguageGroupLocalesA();
2677 test_SetLocaleInfoA();
2678 test_EnumUILanguageA();
2679 test_GetCPInfo();
2680 /* this requires collation table patch to make it MS compatible */
2681 if (0) test_sorting();
2682 }