comctl32: Remove redundant parameter from a helper.
[wine/multimedia.git] / dlls / kernel32 / tests / locale.c
blobf5b77f713731ed2bfb271bcb41531f232688986e
1 /*
2 * Unit tests for locale functions
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
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.
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.
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
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.
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
39 static inline unsigned int strlenW( const WCHAR *str )
41 const WCHAR *s = str;
42 while (*s) s++;
43 return s - str;
46 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
48 if (n <= 0) return 0;
49 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
50 return *str1 - *str2;
53 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
55 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
56 return NULL;
59 static inline int isdigitW( WCHAR wc )
61 WORD type;
62 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
63 return type & C1_DIGIT;
66 /* Some functions are only in later versions of kernel32.dll */
67 static HMODULE hKernel32;
68 static WORD enumCount;
70 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
71 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
72 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
73 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
74 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
75 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
76 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
78 static void InitFunctionPointers(void)
80 hKernel32 = GetModuleHandleA("kernel32");
81 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
82 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
83 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
84 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
85 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
86 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
87 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
90 #define eq(received, expected, label, type) \
91 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
92 (label), (received), (expected))
94 #define BUFFER_SIZE 128
95 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
97 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
98 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
99 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
100 "Expected '%s', got '%s'\n", Expected, buffer)
102 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
103 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
104 SetLastError(0xdeadbeef); buffer[0] = '\0'
105 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
106 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
108 #define NUO LOCALE_NOUSEROVERRIDE
110 static void test_GetLocaleInfoA(void)
112 int ret;
113 int len;
114 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
115 char buffer[BUFFER_SIZE];
116 char expected[BUFFER_SIZE];
118 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
120 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
121 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
122 assumes SUBLANG_NEUTRAL for zh */
123 memset(expected, 0, COUNTOF(expected));
124 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
125 SetLastError(0xdeadbeef);
126 memset(buffer, 0, COUNTOF(buffer));
127 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
128 ok((ret == len) && !lstrcmpA(buffer, expected),
129 "got %d with '%s' (expected %d with '%s')\n",
130 ret, buffer, len, expected);
132 memset(expected, 0, COUNTOF(expected));
133 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
134 if (len) {
135 SetLastError(0xdeadbeef);
136 memset(buffer, 0, COUNTOF(buffer));
137 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
138 ok((ret == len) && !lstrcmpA(buffer, expected),
139 "got %d with '%s' (expected %d with '%s')\n",
140 ret, buffer, len, expected);
142 else
143 win_skip("LANG_ARABIC not installed\n");
145 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
146 memset(expected, 0, COUNTOF(expected));
147 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
148 SetLastError(0xdeadbeef);
149 memset(buffer, 0, COUNTOF(buffer));
150 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
151 ok((ret == len) && !lstrcmpA(buffer, expected),
152 "got %d with '%s' (expected %d with '%s')\n",
153 ret, buffer, len, expected);
156 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
157 * partially fill the buffer even if it is too short. See bug 637.
159 SetLastError(0xdeadbeef);
160 memset(buffer, 0, COUNTOF(buffer));
161 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
162 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
164 SetLastError(0xdeadbeef);
165 memset(buffer, 0, COUNTOF(buffer));
166 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
167 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
168 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
169 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
171 SetLastError(0xdeadbeef);
172 memset(buffer, 0, COUNTOF(buffer));
173 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
174 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
175 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
178 static void test_GetLocaleInfoW(void)
180 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
181 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
182 WCHAR bufferW[80], buffer2W[80];
183 CHAR bufferA[80];
184 DWORD ret;
185 INT i;
187 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
188 if (!ret) {
189 win_skip("GetLocaleInfoW() isn't implemented\n");
190 return;
192 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
193 if (!ret) {
194 win_skip("LANG_RUSSIAN locale data unavailable\n");
195 return;
197 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
198 bufferW, COUNTOF(bufferW));
199 if (!ret) {
200 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
201 return;
204 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
205 bufferA[0] = 'a';
206 SetLastError(0xdeadbeef);
207 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
208 bufferA, COUNTOF(bufferA));
209 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
210 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
211 ok(GetLastError() == ERROR_INVALID_FLAGS,
212 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
214 bufferW[0] = 'a';
215 SetLastError(0xdeadbeef);
216 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
217 bufferW, COUNTOF(bufferW));
218 ok(ret == 0,
219 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
220 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
221 ok(GetLastError() == ERROR_INVALID_FLAGS,
222 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
224 /* yes, test empty 13 month entry too */
225 for (i = 0; i < 12; i++) {
226 bufferW[0] = 0;
227 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
228 bufferW, COUNTOF(bufferW));
229 ok(ret, "Expected non zero result\n");
230 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
231 ret, lstrlenW(bufferW));
232 buffer2W[0] = 0;
233 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
234 buffer2W, COUNTOF(buffer2W));
235 ok(ret, "Expected non zero result\n");
236 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
237 ret, lstrlenW(buffer2W));
239 ok(lstrcmpW(bufferW, buffer2W) != 0,
240 "Expected genitive name to differ, got the same for month %d\n", i+1);
242 /* for locale without genitive names nominative returned in both cases */
243 bufferW[0] = 0;
244 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
245 bufferW, COUNTOF(bufferW));
246 ok(ret, "Expected non zero result\n");
247 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
248 ret, lstrlenW(bufferW));
249 buffer2W[0] = 0;
250 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
251 buffer2W, COUNTOF(buffer2W));
252 ok(ret, "Expected non zero result\n");
253 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
254 ret, lstrlenW(buffer2W));
256 ok(lstrcmpW(bufferW, buffer2W) == 0,
257 "Expected same names, got different for month %d\n", i+1);
261 static void test_GetTimeFormatA(void)
263 int ret;
264 SYSTEMTIME curtime;
265 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
266 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
268 memset(&curtime, 2, sizeof(SYSTEMTIME));
269 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
270 SetLastError(0xdeadbeef);
271 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
272 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
273 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
275 curtime.wHour = 8;
276 curtime.wMinute = 56;
277 curtime.wSecond = 13;
278 curtime.wMilliseconds = 22;
279 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
280 SetLastError(0xdeadbeef);
281 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
282 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
283 EXPECT_LENA; EXPECT_EQA;
285 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
286 SetLastError(0xdeadbeef);
287 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
288 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
289 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
291 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
292 SetLastError(0xdeadbeef);
293 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
294 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
295 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
297 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
298 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
299 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
300 EXPECT_LENA;
302 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
303 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
304 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
305 EXPECT_LENA; EXPECT_EQA;
307 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
308 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
309 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
310 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
311 "Expected '', got '%s'\n", buffer );
313 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
314 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
315 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
316 EXPECT_LENA; EXPECT_EQA;
318 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
319 strcpy(Expected, "8:56 AM");
320 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
321 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
322 EXPECT_LENA; EXPECT_EQA;
324 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
325 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
326 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
327 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
328 "Expected '8.@:56AM', got '%s'\n", buffer );
330 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
331 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
332 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
333 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
334 "Expected '', got '%s'\n", buffer );
336 STRINGSA("t/tt", "A/AM"); /* AM time marker */
337 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
338 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
339 EXPECT_LENA; EXPECT_EQA;
341 curtime.wHour = 13;
342 STRINGSA("t/tt", "P/PM"); /* PM time marker */
343 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
344 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
345 EXPECT_LENA; EXPECT_EQA;
347 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
348 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
349 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
350 EXPECT_LENA; EXPECT_EQA;
352 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
353 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
354 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
355 EXPECT_LENA; EXPECT_EQA;
357 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
358 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
359 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
360 EXPECT_LENA; EXPECT_EQA;
362 curtime.wHour = 14; /* change this to 14 or 2pm */
363 curtime.wMinute = 5;
364 curtime.wSecond = 3;
365 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 */
366 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
368 EXPECT_LENA; EXPECT_EQA;
370 curtime.wHour = 0;
371 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
372 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
373 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
374 EXPECT_LENA; EXPECT_EQA;
376 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
377 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
378 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
379 EXPECT_LENA; EXPECT_EQA;
381 /* try to convert formatting strings with more than two letters
382 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
383 * NOTE: We expect any letter for which there is an upper case value
384 * we should see a replacement. For letters that DO NOT have
385 * upper case values we should see NO REPLACEMENT.
387 curtime.wHour = 8;
388 curtime.wMinute = 56;
389 curtime.wSecond = 13;
390 curtime.wMilliseconds = 22;
391 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
392 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
393 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
394 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
395 EXPECT_LENA; EXPECT_EQA;
397 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
398 strcpy(buffer, "text");
399 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
400 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
401 EXPECT_EQA;
403 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
404 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
405 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
406 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
407 EXPECT_LENA; EXPECT_EQA;
409 STRINGSA("'''", "'"); /* invalid quoted string */
410 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
411 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
412 EXPECT_LENA; EXPECT_EQA;
414 /* test that msdn suggested single quotation usage works as expected */
415 STRINGSA("''''", "'"); /* single quote mark */
416 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
417 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
418 EXPECT_LENA; EXPECT_EQA;
420 STRINGSA("''HHHHHH", "08"); /* Normal use */
421 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
422 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
423 EXPECT_LENA; EXPECT_EQA;
425 /* and test for normal use of the single quotation mark */
426 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
427 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
428 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
429 EXPECT_LENA; EXPECT_EQA;
431 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
432 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
433 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
434 EXPECT_LENA; EXPECT_EQA;
436 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
437 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
438 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
439 EXPECT_LENA; EXPECT_EQA;
441 curtime.wHour = 25;
442 STRINGSA("'123'tt", ""); /* Invalid time */
443 SetLastError(0xdeadbeef);
444 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
445 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
448 curtime.wHour = 12;
449 curtime.wMonth = 60; /* Invalid */
450 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
451 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
452 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
453 EXPECT_LENA; EXPECT_EQA;
456 static void test_GetDateFormatA(void)
458 int ret;
459 SYSTEMTIME curtime;
460 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
461 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
462 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
463 char Broken[BUFFER_SIZE];
464 char short_day[10], month[10], genitive_month[10];
466 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
467 STRINGSA("ddd',' MMM dd yy","");
468 SetLastError(0xdeadbeef);
469 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
470 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
471 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
473 curtime.wYear = 2002;
474 curtime.wMonth = 5;
475 curtime.wDay = 4;
476 curtime.wDayOfWeek = 3;
477 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
478 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
479 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
480 EXPECT_LENA; EXPECT_EQA;
482 /* Same as above but with LOCALE_NOUSEROVERRIDE */
483 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
484 SetLastError(0xdeadbeef);
485 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
486 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
487 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
488 EXPECT_EQA;
490 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
491 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
493 EXPECT_LENA; EXPECT_EQA;
495 curtime.wHour = 36; /* Invalid */
496 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
497 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
498 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
499 EXPECT_LENA; EXPECT_EQA;
501 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
502 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
503 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
504 EXPECT_EQA;
506 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
507 SetLastError(0xdeadbeef);
508 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
509 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
510 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
512 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
513 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
514 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
515 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
516 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
518 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
519 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
520 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
521 EXPECT_LENA; EXPECT_EQA;
523 /* test for expected DATE_YEARMONTH behavior with null format */
524 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
525 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
526 SetLastError(0xdeadbeef);
527 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
528 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
529 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
530 EXPECT_EQA;
532 /* Test that using invalid DATE_* flags results in the correct error */
533 /* and return values */
534 STRINGSA("m/d/y", ""); /* Invalid flags */
535 SetLastError(0xdeadbeef);
536 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
537 &curtime, input, buffer, COUNTOF(buffer));
538 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
539 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
541 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
542 if (!ret)
544 win_skip("LANG_RUSSIAN locale data unavailable\n");
545 return;
548 /* month part should be in genitive form */
549 strcpy(genitive_month, buffer + 2);
550 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
551 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
552 strcpy(month, buffer);
553 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
555 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
556 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
557 strcpy(short_day, buffer);
559 STRINGSA("dd MMMMddd dd", "");
560 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
561 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
562 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
563 EXPECT_EQA;
565 STRINGSA("MMMMddd dd", "");
566 sprintf(Expected, "%s%s 04", month, short_day);
567 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
568 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
569 EXPECT_EQA;
571 STRINGSA("MMMMddd", "");
572 sprintf(Expected, "%s%s", month, short_day);
573 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
574 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
575 EXPECT_EQA;
577 STRINGSA("MMMMdd", "");
578 sprintf(Expected, "%s04", genitive_month);
579 sprintf(Broken, "%s04", month);
580 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
581 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
582 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
583 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
584 "Expected '%s', got '%s'\n", Expected, buffer);
586 STRINGSA("MMMMdd ddd", "");
587 sprintf(Expected, "%s04 %s", genitive_month, short_day);
588 sprintf(Broken, "%s04 %s", month, short_day);
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);
595 STRINGSA("dd dddMMMM", "");
596 sprintf(Expected, "04 %s%s", short_day, month);
597 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
598 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
599 EXPECT_EQA;
601 STRINGSA("dd dddMMMM ddd MMMMdd", "");
602 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
603 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
604 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
605 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
606 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
607 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
608 "Expected '%s', got '%s'\n", Expected, buffer);
610 /* with literal part */
611 STRINGSA("ddd',' MMMM dd", "");
612 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
613 sprintf(Broken, "%s, %s 04", short_day, month);
614 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
615 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
616 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
617 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
618 "Expected '%s', got '%s'\n", Expected, buffer);
621 static void test_GetDateFormatW(void)
623 int ret;
624 SYSTEMTIME curtime;
625 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
626 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
628 STRINGSW("",""); /* If flags is not zero then format must be NULL */
629 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
630 input, buffer, COUNTOF(buffer));
631 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
633 win_skip("GetDateFormatW is not implemented\n");
634 return;
636 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
637 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
638 EXPECT_EQW;
640 STRINGSW("",""); /* NULL buffer, len > 0 */
641 SetLastError(0xdeadbeef);
642 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
643 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
644 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
646 STRINGSW("",""); /* NULL buffer, len == 0 */
647 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
648 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
649 EXPECT_LENW; EXPECT_EQW;
651 curtime.wYear = 2002;
652 curtime.wMonth = 10;
653 curtime.wDay = 23;
654 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
655 curtime.wHour = 65432; /* Invalid */
656 curtime.wMinute = 34512; /* Invalid */
657 curtime.wSecond = 65535; /* Invalid */
658 curtime.wMilliseconds = 12345;
659 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
660 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
661 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
662 EXPECT_LENW; EXPECT_EQW;
664 /* Limit tests */
666 curtime.wYear = 1601;
667 curtime.wMonth = 1;
668 curtime.wDay = 1;
669 curtime.wDayOfWeek = 0; /* Irrelevant */
670 curtime.wHour = 0;
671 curtime.wMinute = 0;
672 curtime.wSecond = 0;
673 curtime.wMilliseconds = 0;
674 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
675 SetLastError(0xdeadbeef);
676 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
677 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
678 EXPECT_LENW; EXPECT_EQW;
680 curtime.wYear = 1600;
681 curtime.wMonth = 12;
682 curtime.wDay = 31;
683 curtime.wDayOfWeek = 0; /* Irrelevant */
684 curtime.wHour = 23;
685 curtime.wMinute = 59;
686 curtime.wSecond = 59;
687 curtime.wMilliseconds = 999;
688 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
689 SetLastError(0xdeadbeef);
690 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
691 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
692 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
696 #define CY_POS_LEFT 0
697 #define CY_POS_RIGHT 1
698 #define CY_POS_LEFT_SPACE 2
699 #define CY_POS_RIGHT_SPACE 3
701 static void test_GetCurrencyFormatA(void)
703 static char szDot[] = { '.', '\0' };
704 static char szComma[] = { ',', '\0' };
705 static char szDollar[] = { '$', '\0' };
706 int ret;
707 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
708 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
709 CURRENCYFMTA format;
711 memset(&format, 0, sizeof(format));
713 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
714 SetLastError(0xdeadbeef);
715 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
716 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
717 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
719 STRINGSA("23,53",""); /* Invalid character --> Error */
720 SetLastError(0xdeadbeef);
721 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
722 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
723 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
725 STRINGSA("--",""); /* Double '-' --> Error */
726 SetLastError(0xdeadbeef);
727 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
728 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
729 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
731 STRINGSA("0-",""); /* Trailing '-' --> Error */
732 SetLastError(0xdeadbeef);
733 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
734 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
735 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
737 STRINGSA("0..",""); /* Double '.' --> Error */
738 SetLastError(0xdeadbeef);
739 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
740 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
741 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
743 STRINGSA(" 0.1",""); /* Leading space --> Error */
744 SetLastError(0xdeadbeef);
745 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
746 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
747 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
749 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
750 SetLastError(0xdeadbeef);
751 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
752 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
753 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
755 STRINGSA("2353",""); /* Format and flags given --> Error */
756 SetLastError(0xdeadbeef);
757 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
758 ok( !ret, "Expected ret == 0, got %d\n", ret);
759 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
760 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
762 STRINGSA("2353",""); /* Invalid format --> Error */
763 SetLastError(0xdeadbeef);
764 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
765 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
766 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
768 STRINGSA("2353","$2,353.00"); /* Valid number */
769 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
770 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
771 EXPECT_LENA; EXPECT_EQA;
773 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
774 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
775 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
776 EXPECT_LENA; EXPECT_EQA;
778 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
779 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
780 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781 EXPECT_LENA; EXPECT_EQA;
783 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
784 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENA; EXPECT_EQA;
788 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
789 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
790 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
791 EXPECT_LENA; EXPECT_EQA;
793 format.NumDigits = 0; /* No decimal separator */
794 format.LeadingZero = 0;
795 format.Grouping = 0; /* No grouping char */
796 format.NegativeOrder = 0;
797 format.PositiveOrder = CY_POS_LEFT;
798 format.lpDecimalSep = szDot;
799 format.lpThousandSep = szComma;
800 format.lpCurrencySymbol = szDollar;
802 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
803 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
804 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
805 EXPECT_LENA; EXPECT_EQA;
807 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
808 STRINGSA("2353","$2353.0");
809 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
810 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
811 EXPECT_LENA; EXPECT_EQA;
813 format.Grouping = 2; /* Group by 100's */
814 STRINGSA("2353","$23,53.0");
815 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
816 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
817 EXPECT_LENA; EXPECT_EQA;
819 STRINGSA("235","$235.0"); /* Grouping of a positive number */
820 format.Grouping = 3;
821 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
822 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
823 EXPECT_LENA; EXPECT_EQA;
825 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
826 format.NegativeOrder = 2;
827 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
828 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
829 EXPECT_LENA; EXPECT_EQA;
831 format.LeadingZero = 1; /* Always provide leading zero */
832 STRINGSA(".5","$0.5");
833 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
834 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
835 EXPECT_LENA; EXPECT_EQA;
837 format.PositiveOrder = CY_POS_RIGHT;
838 STRINGSA("1","1.0$");
839 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
840 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
841 EXPECT_LENA; EXPECT_EQA;
843 format.PositiveOrder = CY_POS_LEFT_SPACE;
844 STRINGSA("1","$ 1.0");
845 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
846 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
847 EXPECT_LENA; EXPECT_EQA;
849 format.PositiveOrder = CY_POS_RIGHT_SPACE;
850 STRINGSA("1","1.0 $");
851 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
852 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
853 EXPECT_LENA; EXPECT_EQA;
855 format.NegativeOrder = 0;
856 STRINGSA("-1","($1.0)");
857 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
858 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
859 EXPECT_LENA; EXPECT_EQA;
861 format.NegativeOrder = 1;
862 STRINGSA("-1","-$1.0");
863 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
864 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
865 EXPECT_LENA; EXPECT_EQA;
867 format.NegativeOrder = 2;
868 STRINGSA("-1","$-1.0");
869 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
870 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
871 EXPECT_LENA; EXPECT_EQA;
873 format.NegativeOrder = 3;
874 STRINGSA("-1","$1.0-");
875 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
876 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
877 EXPECT_LENA; EXPECT_EQA;
879 format.NegativeOrder = 4;
880 STRINGSA("-1","(1.0$)");
881 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
882 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
883 EXPECT_LENA; EXPECT_EQA;
885 format.NegativeOrder = 5;
886 STRINGSA("-1","-1.0$");
887 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
888 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
889 EXPECT_LENA; EXPECT_EQA;
891 format.NegativeOrder = 6;
892 STRINGSA("-1","1.0-$");
893 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
894 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
895 EXPECT_LENA; EXPECT_EQA;
897 format.NegativeOrder = 7;
898 STRINGSA("-1","1.0$-");
899 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
900 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
901 EXPECT_LENA; EXPECT_EQA;
903 format.NegativeOrder = 8;
904 STRINGSA("-1","-1.0 $");
905 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
906 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
907 EXPECT_LENA; EXPECT_EQA;
909 format.NegativeOrder = 9;
910 STRINGSA("-1","-$ 1.0");
911 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
912 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
913 EXPECT_LENA; EXPECT_EQA;
915 format.NegativeOrder = 10;
916 STRINGSA("-1","1.0 $-");
917 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
918 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919 EXPECT_LENA; EXPECT_EQA;
921 format.NegativeOrder = 11;
922 STRINGSA("-1","$ 1.0-");
923 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
924 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
925 EXPECT_LENA; EXPECT_EQA;
927 format.NegativeOrder = 12;
928 STRINGSA("-1","$ -1.0");
929 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
930 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
931 EXPECT_LENA; EXPECT_EQA;
933 format.NegativeOrder = 13;
934 STRINGSA("-1","1.0- $");
935 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
936 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
937 EXPECT_LENA; EXPECT_EQA;
939 format.NegativeOrder = 14;
940 STRINGSA("-1","($ 1.0)");
941 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
942 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
943 EXPECT_LENA; EXPECT_EQA;
945 format.NegativeOrder = 15;
946 STRINGSA("-1","(1.0 $)");
947 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
948 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
949 EXPECT_LENA; EXPECT_EQA;
952 #define NEG_PARENS 0 /* "(1.1)" */
953 #define NEG_LEFT 1 /* "-1.1" */
954 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
955 #define NEG_RIGHT 3 /* "1.1-" */
956 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
958 static void test_GetNumberFormatA(void)
960 static char szDot[] = { '.', '\0' };
961 static char szComma[] = { ',', '\0' };
962 int ret;
963 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
964 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
965 NUMBERFMTA format;
967 memset(&format, 0, sizeof(format));
969 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
970 SetLastError(0xdeadbeef);
971 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
972 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
973 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
975 STRINGSA("23,53",""); /* Invalid character --> Error */
976 SetLastError(0xdeadbeef);
977 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
978 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
979 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
981 STRINGSA("--",""); /* Double '-' --> Error */
982 SetLastError(0xdeadbeef);
983 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
984 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
985 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
987 STRINGSA("0-",""); /* Trailing '-' --> Error */
988 SetLastError(0xdeadbeef);
989 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
990 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
991 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
993 STRINGSA("0..",""); /* Double '.' --> Error */
994 SetLastError(0xdeadbeef);
995 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
996 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
997 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
999 STRINGSA(" 0.1",""); /* Leading space --> Error */
1000 SetLastError(0xdeadbeef);
1001 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1002 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1003 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1005 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1006 SetLastError(0xdeadbeef);
1007 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1008 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1009 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1011 STRINGSA("2353",""); /* Format and flags given --> Error */
1012 SetLastError(0xdeadbeef);
1013 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1014 ok( !ret, "Expected ret == 0, got %d\n", ret);
1015 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1016 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1018 STRINGSA("2353",""); /* Invalid format --> Error */
1019 SetLastError(0xdeadbeef);
1020 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1021 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1022 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1024 STRINGSA("2353","2,353.00"); /* Valid number */
1025 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1026 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1027 EXPECT_LENA; EXPECT_EQA;
1029 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1030 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1031 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1032 EXPECT_LENA; EXPECT_EQA;
1034 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1035 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1036 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1037 EXPECT_LENA; EXPECT_EQA;
1039 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1040 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1041 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1042 EXPECT_LENA; EXPECT_EQA;
1044 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1045 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1046 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1047 EXPECT_LENA; EXPECT_EQA;
1049 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1050 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1051 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1052 EXPECT_LENA; EXPECT_EQA;
1054 format.NumDigits = 0; /* No decimal separator */
1055 format.LeadingZero = 0;
1056 format.Grouping = 0; /* No grouping char */
1057 format.NegativeOrder = 0;
1058 format.lpDecimalSep = szDot;
1059 format.lpThousandSep = szComma;
1061 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1062 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1063 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1064 EXPECT_LENA; EXPECT_EQA;
1066 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1067 STRINGSA("2353","2353.0");
1068 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1069 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1070 EXPECT_LENA; EXPECT_EQA;
1072 format.Grouping = 2; /* Group by 100's */
1073 STRINGSA("2353","23,53.0");
1074 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1075 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1076 EXPECT_LENA; EXPECT_EQA;
1078 STRINGSA("235","235.0"); /* Grouping of a positive number */
1079 format.Grouping = 3;
1080 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1081 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1082 EXPECT_LENA; EXPECT_EQA;
1084 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1085 format.NegativeOrder = NEG_LEFT;
1086 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1087 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1088 EXPECT_LENA; EXPECT_EQA;
1090 format.LeadingZero = 1; /* Always provide leading zero */
1091 STRINGSA(".5","0.5");
1092 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1093 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1094 EXPECT_LENA; EXPECT_EQA;
1096 format.NegativeOrder = NEG_PARENS;
1097 STRINGSA("-1","(1.0)");
1098 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1099 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1100 EXPECT_LENA; EXPECT_EQA;
1102 format.NegativeOrder = NEG_LEFT;
1103 STRINGSA("-1","-1.0");
1104 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1105 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1106 EXPECT_LENA; EXPECT_EQA;
1108 format.NegativeOrder = NEG_LEFT_SPACE;
1109 STRINGSA("-1","- 1.0");
1110 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1111 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1112 EXPECT_LENA; EXPECT_EQA;
1114 format.NegativeOrder = NEG_RIGHT;
1115 STRINGSA("-1","1.0-");
1116 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1117 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1118 EXPECT_LENA; EXPECT_EQA;
1120 format.NegativeOrder = NEG_RIGHT_SPACE;
1121 STRINGSA("-1","1.0 -");
1122 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1123 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1124 EXPECT_LENA; EXPECT_EQA;
1126 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1128 if (IsValidLocale(lcid, 0))
1130 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1131 Expected[3] = 160; /* Non breaking space */
1132 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1133 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1134 EXPECT_LENA; EXPECT_EQA;
1138 struct comparestringa_entry {
1139 LCID lcid;
1140 DWORD flags;
1141 const char *first;
1142 int first_len;
1143 const char *second;
1144 int second_len;
1145 int ret;
1148 static const struct comparestringa_entry comparestringa_data[] = {
1149 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1150 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1151 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1152 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1153 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1154 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1155 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1156 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1157 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1158 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1159 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1160 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1161 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1162 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1163 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1164 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1165 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1166 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1167 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1168 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1169 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1170 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1171 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1172 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1173 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1174 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1175 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1176 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1177 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1178 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1181 static void test_CompareStringA(void)
1183 int ret, i;
1184 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1186 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1188 const struct comparestringa_entry *entry = &comparestringa_data[i];
1190 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1191 entry->second, entry->second_len);
1192 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1195 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1196 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1198 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1199 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1201 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1202 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1204 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1205 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1207 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1209 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1210 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1212 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1213 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1215 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1216 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1218 /* test for CompareStringA flags */
1219 SetLastError(0xdeadbeef);
1220 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1221 ok(GetLastError() == ERROR_INVALID_FLAGS,
1222 "unexpected error code %d\n", GetLastError());
1223 ok(!ret, "CompareStringA must fail with invalid flag\n");
1225 SetLastError(0xdeadbeef);
1226 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1227 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1228 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1229 /* end of test for CompareStringA flags */
1231 ret = lstrcmpA("", "");
1232 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1234 ret = lstrcmpA(NULL, NULL);
1235 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1237 ret = lstrcmpA("", NULL);
1238 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1240 ret = lstrcmpA(NULL, "");
1241 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1244 if (0) { /* this requires collation table patch to make it MS compatible */
1245 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1246 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1248 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1249 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1251 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1252 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1254 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1255 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1257 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1258 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1260 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1261 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1263 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1264 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1266 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1267 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1269 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1270 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1272 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1273 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1275 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1276 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1278 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1279 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1283 /* WinXP handles embedded NULLs differently than earlier versions */
1284 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1285 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1287 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1288 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1290 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1291 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1293 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1294 ok(ret == CSTR_EQUAL || /* win2k */
1295 ret == CSTR_GREATER_THAN,
1296 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1298 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1299 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1301 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1302 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1304 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1305 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1307 ret = lstrcmpi("#", ".");
1308 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1310 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1312 /* \xB9 character lies between a and b */
1313 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1314 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1315 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1316 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1319 static void test_LCMapStringA(void)
1321 int ret, ret2;
1322 char buf[256], buf2[256];
1323 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1324 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1325 static const char symbols_stripped[] = "justateststring1";
1327 SetLastError(0xdeadbeef);
1328 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1329 lower_case, -1, buf, sizeof(buf));
1330 ok(ret == lstrlenA(lower_case) + 1,
1331 "ret %d, error %d, expected value %d\n",
1332 ret, GetLastError(), lstrlenA(lower_case) + 1);
1333 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1335 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1336 upper_case, -1, buf, sizeof(buf));
1337 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1338 ok(GetLastError() == ERROR_INVALID_FLAGS,
1339 "unexpected error code %d\n", GetLastError());
1341 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1342 upper_case, -1, buf, sizeof(buf));
1343 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1344 ok(GetLastError() == ERROR_INVALID_FLAGS,
1345 "unexpected error code %d\n", GetLastError());
1347 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1348 upper_case, -1, buf, sizeof(buf));
1349 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1350 ok(GetLastError() == ERROR_INVALID_FLAGS,
1351 "unexpected error code %d\n", GetLastError());
1353 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1354 upper_case, -1, buf, sizeof(buf));
1355 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1356 ok(GetLastError() == ERROR_INVALID_FLAGS,
1357 "unexpected error code %d\n", GetLastError());
1359 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1360 SetLastError(0xdeadbeef);
1361 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1362 upper_case, -1, buf, sizeof(buf));
1363 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1364 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1366 /* test LCMAP_LOWERCASE */
1367 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1368 upper_case, -1, buf, sizeof(buf));
1369 ok(ret == lstrlenA(upper_case) + 1,
1370 "ret %d, error %d, expected value %d\n",
1371 ret, GetLastError(), lstrlenA(upper_case) + 1);
1372 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1374 /* test LCMAP_UPPERCASE */
1375 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1376 lower_case, -1, buf, sizeof(buf));
1377 ok(ret == lstrlenA(lower_case) + 1,
1378 "ret %d, error %d, expected value %d\n",
1379 ret, GetLastError(), lstrlenA(lower_case) + 1);
1380 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1382 /* test buffer overflow */
1383 SetLastError(0xdeadbeef);
1384 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1385 lower_case, -1, buf, 4);
1386 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1387 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1389 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1390 lstrcpyA(buf, lower_case);
1391 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1392 buf, -1, buf, sizeof(buf));
1393 if (!ret) /* Win9x */
1394 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1395 else
1397 ok(ret == lstrlenA(lower_case) + 1,
1398 "ret %d, error %d, expected value %d\n",
1399 ret, GetLastError(), lstrlenA(lower_case) + 1);
1400 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1402 lstrcpyA(buf, upper_case);
1403 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1404 buf, -1, buf, sizeof(buf));
1405 if (!ret) /* Win9x */
1406 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1407 else
1409 ok(ret == lstrlenA(upper_case) + 1,
1410 "ret %d, error %d, expected value %d\n",
1411 ret, GetLastError(), lstrlenA(lower_case) + 1);
1412 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1415 /* otherwise src == dst should fail */
1416 SetLastError(0xdeadbeef);
1417 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1418 buf, 10, buf, sizeof(buf));
1419 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1420 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1421 "unexpected error code %d\n", GetLastError());
1422 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1424 /* test whether '\0' is always appended */
1425 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1426 upper_case, -1, buf, sizeof(buf));
1427 ok(ret, "LCMapStringA must succeed\n");
1428 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1429 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1430 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1431 ok(ret2, "LCMapStringA must succeed\n");
1432 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1433 ok(ret == ret2, "lengths of sort keys must be equal\n");
1434 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1436 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1437 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1438 upper_case, -1, buf, sizeof(buf));
1439 ok(ret, "LCMapStringA must succeed\n");
1440 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1441 lower_case, -1, buf2, sizeof(buf2));
1442 ok(ret2, "LCMapStringA must succeed\n");
1443 ok(ret == ret2, "lengths of sort keys must be equal\n");
1444 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1446 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1447 results from plain LCMAP_SORTKEY on Vista */
1449 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1450 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1451 lower_case, -1, buf, sizeof(buf));
1452 ok(ret, "LCMapStringA must succeed\n");
1453 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1454 symbols_stripped, -1, buf2, sizeof(buf2));
1455 ok(ret2, "LCMapStringA must succeed\n");
1456 ok(ret == ret2, "lengths of sort keys must be equal\n");
1457 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1459 /* test NORM_IGNORENONSPACE */
1460 lstrcpyA(buf, "foo");
1461 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1462 lower_case, -1, buf, sizeof(buf));
1463 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1464 lstrlenA(lower_case) + 1, ret);
1465 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1467 /* test NORM_IGNORESYMBOLS */
1468 lstrcpyA(buf, "foo");
1469 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1470 lower_case, -1, buf, sizeof(buf));
1471 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1472 lstrlenA(symbols_stripped) + 1, ret);
1473 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1475 /* test srclen = 0 */
1476 SetLastError(0xdeadbeef);
1477 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1478 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1479 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1480 "unexpected error code %d\n", GetLastError());
1483 static void test_LCMapStringW(void)
1485 int ret, ret2;
1486 WCHAR buf[256], buf2[256];
1487 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1488 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};
1489 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};
1490 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1491 static const WCHAR fooW[] = {'f','o','o',0};
1493 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1494 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1495 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1497 win_skip("LCMapStringW is not implemented\n");
1498 return;
1500 if (broken(ret))
1501 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1502 else
1504 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1505 ok(GetLastError() == ERROR_INVALID_FLAGS,
1506 "unexpected error code %d\n", GetLastError());
1509 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1510 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1511 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1512 ok(GetLastError() == ERROR_INVALID_FLAGS,
1513 "unexpected error code %d\n", GetLastError());
1515 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1516 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1517 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1518 ok(GetLastError() == ERROR_INVALID_FLAGS,
1519 "unexpected error code %d\n", GetLastError());
1521 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1522 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1523 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1524 ok(GetLastError() == ERROR_INVALID_FLAGS,
1525 "unexpected error code %d\n", GetLastError());
1527 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1528 SetLastError(0xdeadbeef);
1529 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1530 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1531 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1532 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1534 /* test LCMAP_LOWERCASE */
1535 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1536 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1537 ok(ret == lstrlenW(upper_case) + 1,
1538 "ret %d, error %d, expected value %d\n",
1539 ret, GetLastError(), lstrlenW(upper_case) + 1);
1540 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1542 /* test LCMAP_UPPERCASE */
1543 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1544 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1545 ok(ret == lstrlenW(lower_case) + 1,
1546 "ret %d, error %d, expected value %d\n",
1547 ret, GetLastError(), lstrlenW(lower_case) + 1);
1548 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1550 /* test buffer overflow */
1551 SetLastError(0xdeadbeef);
1552 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1553 lower_case, -1, buf, 4);
1554 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1555 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1557 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1558 lstrcpyW(buf, lower_case);
1559 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1560 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1561 ok(ret == lstrlenW(lower_case) + 1,
1562 "ret %d, error %d, expected value %d\n",
1563 ret, GetLastError(), lstrlenW(lower_case) + 1);
1564 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1566 lstrcpyW(buf, upper_case);
1567 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1568 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1569 ok(ret == lstrlenW(upper_case) + 1,
1570 "ret %d, error %d, expected value %d\n",
1571 ret, GetLastError(), lstrlenW(lower_case) + 1);
1572 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1574 /* otherwise src == dst should fail */
1575 SetLastError(0xdeadbeef);
1576 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1577 buf, 10, buf, sizeof(buf));
1578 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1579 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1580 "unexpected error code %d\n", GetLastError());
1581 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1583 /* test whether '\0' is always appended */
1584 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1585 upper_case, -1, buf, sizeof(buf));
1586 ok(ret, "LCMapStringW must succeed\n");
1587 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1588 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1589 ok(ret, "LCMapStringW must succeed\n");
1590 ok(ret == ret2, "lengths of sort keys must be equal\n");
1591 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1593 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1594 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1595 upper_case, -1, buf, sizeof(buf));
1596 ok(ret, "LCMapStringW must succeed\n");
1597 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1598 lower_case, -1, buf2, sizeof(buf2));
1599 ok(ret2, "LCMapStringW must succeed\n");
1600 ok(ret == ret2, "lengths of sort keys must be equal\n");
1601 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1603 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1604 results from plain LCMAP_SORTKEY on Vista */
1606 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1607 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1608 lower_case, -1, buf, sizeof(buf));
1609 ok(ret, "LCMapStringW must succeed\n");
1610 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1611 symbols_stripped, -1, buf2, sizeof(buf2));
1612 ok(ret2, "LCMapStringW must succeed\n");
1613 ok(ret == ret2, "lengths of sort keys must be equal\n");
1614 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1616 /* test NORM_IGNORENONSPACE */
1617 lstrcpyW(buf, fooW);
1618 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1619 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1620 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1621 lstrlenW(lower_case) + 1, ret);
1622 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1624 /* test NORM_IGNORESYMBOLS */
1625 lstrcpyW(buf, fooW);
1626 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1627 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1628 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1629 lstrlenW(symbols_stripped) + 1, ret);
1630 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1632 /* test srclen = 0 */
1633 SetLastError(0xdeadbeef);
1634 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1635 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1636 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1637 "unexpected error code %d\n", GetLastError());
1640 /* this requires collation table patch to make it MS compatible */
1641 static const char * const strings_sorted[] =
1643 "'",
1644 "-",
1645 "!",
1646 "\"",
1647 ".",
1648 ":",
1649 "\\",
1650 "_",
1651 "`",
1652 "{",
1653 "}",
1654 "+",
1655 "0",
1656 "1",
1657 "2",
1658 "3",
1659 "4",
1660 "5",
1661 "6",
1662 "7",
1663 "8",
1664 "9",
1665 "a",
1666 "A",
1667 "b",
1668 "B",
1669 "c",
1673 static const char * const strings[] =
1675 "C",
1676 "\"",
1677 "9",
1678 "'",
1679 "}",
1680 "-",
1681 "7",
1682 "+",
1683 "`",
1684 "1",
1685 "a",
1686 "5",
1687 "\\",
1688 "8",
1689 "B",
1690 "3",
1691 "_",
1692 "6",
1693 "{",
1694 "2",
1695 "c",
1696 "4",
1697 "!",
1698 "0",
1699 "A",
1700 ":",
1701 "b",
1705 static int compare_string1(const void *e1, const void *e2)
1707 const char *s1 = *(const char *const *)e1;
1708 const char *s2 = *(const char *const *)e2;
1710 return lstrcmpA(s1, s2);
1713 static int compare_string2(const void *e1, const void *e2)
1715 const char *s1 = *(const char *const *)e1;
1716 const char *s2 = *(const char *const *)e2;
1718 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1721 static int compare_string3(const void *e1, const void *e2)
1723 const char *s1 = *(const char *const *)e1;
1724 const char *s2 = *(const char *const *)e2;
1725 char key1[256], key2[256];
1727 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1728 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1729 return strcmp(key1, key2);
1732 static void test_sorting(void)
1734 char buf[256];
1735 char **str_buf = (char **)buf;
1736 int i;
1738 assert(sizeof(buf) >= sizeof(strings));
1740 /* 1. sort using lstrcmpA */
1741 memcpy(buf, strings, sizeof(strings));
1742 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1743 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1745 ok(!strcmp(strings_sorted[i], str_buf[i]),
1746 "qsort using lstrcmpA failed for element %d\n", i);
1748 /* 2. sort using CompareStringA */
1749 memcpy(buf, strings, sizeof(strings));
1750 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1751 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1753 ok(!strcmp(strings_sorted[i], str_buf[i]),
1754 "qsort using CompareStringA failed for element %d\n", i);
1756 /* 3. sort using sort keys */
1757 memcpy(buf, strings, sizeof(strings));
1758 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1759 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1761 ok(!strcmp(strings_sorted[i], str_buf[i]),
1762 "qsort using sort keys failed for element %d\n", i);
1766 static void test_FoldStringA(void)
1768 int ret, i, j;
1769 BOOL is_special;
1770 char src[256], dst[256];
1771 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1772 static const char digits_dst[] = { '1','2','3','\0' };
1773 static const char composite_src[] =
1775 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1776 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1777 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1778 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1779 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1780 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1781 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1782 0xfb,0xfc,0xfd,0xff,'\0'
1784 static const char composite_dst[] =
1786 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1787 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1788 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1789 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1790 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1791 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1792 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1793 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1794 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1795 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1796 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1797 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1798 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1799 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1800 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1802 static const char composite_dst_alt[] =
1804 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1805 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1806 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1807 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1808 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1809 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1810 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1811 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1812 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1813 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1814 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1815 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1816 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1817 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1818 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1820 static const char ligatures_src[] =
1822 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1824 static const char ligatures_dst[] =
1826 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1828 static const struct special
1830 char src;
1831 char dst[4];
1832 } foldczone_special[] =
1834 /* src dst */
1835 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1836 { 0x98, { 0x20, 0x7e, 0x00 } },
1837 { 0x99, { 0x54, 0x4d, 0x00 } },
1838 { 0xa0, { 0x20, 0x00 } },
1839 { 0xa8, { 0x20, 0xa8, 0x00 } },
1840 { 0xaa, { 0x61, 0x00 } },
1841 { 0xaf, { 0x20, 0xaf, 0x00 } },
1842 { 0xb2, { 0x32, 0x00 } },
1843 { 0xb3, { 0x33, 0x00 } },
1844 { 0xb4, { 0x20, 0xb4, 0x00 } },
1845 { 0xb8, { 0x20, 0xb8, 0x00 } },
1846 { 0xb9, { 0x31, 0x00 } },
1847 { 0xba, { 0x6f, 0x00 } },
1848 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1849 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1850 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1851 { 0x00 }
1854 if (!pFoldStringA)
1855 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1857 /* these tests are locale specific */
1858 if (GetACP() != 1252)
1860 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1861 return;
1864 /* MAP_FOLDDIGITS */
1865 SetLastError(0);
1866 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1867 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1869 win_skip("FoldStringA is not implemented\n");
1870 return;
1872 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1873 ok(strcmp(dst, digits_dst) == 0,
1874 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1875 for (i = 1; i < 256; i++)
1877 if (!strchr(digits_src, i))
1879 src[0] = i;
1880 src[1] = '\0';
1881 SetLastError(0);
1882 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1883 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1884 ok(dst[0] == src[0],
1885 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1889 /* MAP_EXPAND_LIGATURES */
1890 SetLastError(0);
1891 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1892 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1893 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1894 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1895 ok(strcmp(dst, ligatures_dst) == 0,
1896 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1897 for (i = 1; i < 256; i++)
1899 if (!strchr(ligatures_src, i))
1901 src[0] = i;
1902 src[1] = '\0';
1903 SetLastError(0);
1904 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1905 if (ret == 3)
1907 /* Vista */
1908 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1909 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1910 "Got %s for %d\n", dst, i);
1912 else
1914 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1915 ok(dst[0] == src[0],
1916 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1922 /* MAP_COMPOSITE */
1923 SetLastError(0);
1924 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1925 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1926 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1927 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1928 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1930 for (i = 1; i < 256; i++)
1932 if (!strchr(composite_src, i))
1934 src[0] = i;
1935 src[1] = '\0';
1936 SetLastError(0);
1937 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1938 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1939 ok(dst[0] == src[0],
1940 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1941 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1945 /* MAP_FOLDCZONE */
1946 for (i = 1; i < 256; i++)
1948 src[0] = i;
1949 src[1] = '\0';
1950 SetLastError(0);
1951 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1952 is_special = FALSE;
1953 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1955 if (foldczone_special[j].src == src[0])
1957 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1958 "Expected ret == 2 or %d, got %d, error %d\n",
1959 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
1960 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
1961 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
1962 (unsigned char)src[0]);
1963 is_special = TRUE;
1966 if (! is_special)
1968 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1969 ok(src[0] == dst[0],
1970 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
1971 (unsigned char)src[0], (unsigned char)dst[0]);
1975 /* MAP_PRECOMPOSED */
1976 for (i = 1; i < 256; i++)
1978 src[0] = i;
1979 src[1] = '\0';
1980 SetLastError(0);
1981 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
1982 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1983 ok(src[0] == dst[0],
1984 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
1985 (unsigned char)src[0], (unsigned char)dst[0]);
1989 static void test_FoldStringW(void)
1991 int ret;
1992 unsigned int i, j;
1993 WCHAR src[256], dst[256], ch, prev_ch = 1;
1994 static const DWORD badFlags[] =
1997 MAP_PRECOMPOSED|MAP_COMPOSITE,
1998 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
1999 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2001 /* Ranges of digits 0-9 : Must be sorted! */
2002 static const WCHAR digitRanges[] =
2004 0x0030, /* '0'-'9' */
2005 0x0660, /* Eastern Arabic */
2006 0x06F0, /* Arabic - Hindu */
2007 0x0966, /* Devengari */
2008 0x09E6, /* Bengalii */
2009 0x0A66, /* Gurmukhi */
2010 0x0AE6, /* Gujarati */
2011 0x0B66, /* Oriya */
2012 0x0BE6, /* Tamil - No 0 */
2013 0x0C66, /* Telugu */
2014 0x0CE6, /* Kannada */
2015 0x0D66, /* Maylayalam */
2016 0x0E50, /* Thai */
2017 0x0ED0, /* Laos */
2018 0x0F29, /* Tibet - 0 is out of sequence */
2019 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2020 0x2080, /* Subscript */
2021 0x245F, /* Circled - 0 is out of sequence */
2022 0x2473, /* Bracketed */
2023 0x2487, /* Full stop */
2024 0x2775, /* Inverted circled - No 0 */
2025 0x277F, /* Patterned circled - No 0 */
2026 0x2789, /* Inverted Patterned circled - No 0 */
2027 0x3020, /* Hangzhou */
2028 0xff10, /* Pliene chasse (?) */
2029 0xffff /* Terminator */
2031 /* Digits which are represented, but out of sequence */
2032 static const WCHAR outOfSequenceDigits[] =
2034 0xB9, /* Superscript 1 */
2035 0xB2, /* Superscript 2 */
2036 0xB3, /* Superscript 3 */
2037 0x0F33, /* Tibetan half zero */
2038 0x24EA, /* Circled 0 */
2039 0x3007, /* Ideographic number zero */
2040 '\0' /* Terminator */
2042 /* Digits in digitRanges for which no representation is available */
2043 static const WCHAR noDigitAvailable[] =
2045 0x0BE6, /* No Tamil 0 */
2046 0x0F29, /* No Tibetan half zero (out of sequence) */
2047 0x2473, /* No Bracketed 0 */
2048 0x2487, /* No 0 Full stop */
2049 0x2775, /* No inverted circled 0 */
2050 0x277F, /* No patterned circled */
2051 0x2789, /* No inverted Patterned circled */
2052 0x3020, /* No Hangzhou 0 */
2053 '\0' /* Terminator */
2055 static const WCHAR foldczone_src[] =
2057 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2058 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2060 static const WCHAR foldczone_dst[] =
2062 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2064 static const WCHAR ligatures_src[] =
2066 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2067 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2068 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2069 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2070 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2071 0xfb04, 0xfb05, 0xfb06, '\0'
2073 static const WCHAR ligatures_dst[] =
2075 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2076 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2077 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2078 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2079 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2080 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2083 if (!pFoldStringW)
2085 win_skip("FoldStringW is not available\n");
2086 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2089 /* Invalid flag combinations */
2090 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2092 src[0] = dst[0] = '\0';
2093 SetLastError(0);
2094 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2095 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2097 win_skip("FoldStringW is not implemented\n");
2098 return;
2100 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2101 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2104 /* src & dst cannot be the same */
2105 SetLastError(0);
2106 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2107 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2108 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2110 /* src can't be NULL */
2111 SetLastError(0);
2112 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2113 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2114 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2116 /* srclen can't be 0 */
2117 SetLastError(0);
2118 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2119 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2120 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2122 /* dstlen can't be < 0 */
2123 SetLastError(0);
2124 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2125 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2126 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2128 /* Ret includes terminating NUL which is appended if srclen = -1 */
2129 SetLastError(0);
2130 src[0] = 'A';
2131 src[1] = '\0';
2132 dst[0] = '\0';
2133 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2134 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2135 ok(dst[0] == 'A' && dst[1] == '\0',
2136 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2137 'A', '\0', ret, dst[0], dst[1], GetLastError());
2139 /* If size is given, result is not NUL terminated */
2140 SetLastError(0);
2141 src[0] = 'A';
2142 src[1] = 'A';
2143 dst[0] = 'X';
2144 dst[1] = 'X';
2145 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2146 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2147 ok(dst[0] == 'A' && dst[1] == 'X',
2148 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2149 'A','X', ret, dst[0], dst[1], GetLastError());
2151 /* MAP_FOLDDIGITS */
2152 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2154 /* Check everything before this range */
2155 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2157 SetLastError(0);
2158 src[0] = ch;
2159 src[1] = dst[0] = '\0';
2160 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2161 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2163 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2164 /* Wine (correctly) maps all Unicode 4.0+ digits */
2165 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2166 (ch >= 0x1369 && ch <= 0x1371),
2167 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2170 if (digitRanges[j] == 0xffff)
2171 break; /* Finished the whole code point space */
2173 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2175 WCHAR c;
2177 /* Map out of sequence characters */
2178 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2179 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2180 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2181 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2182 else c = ch;
2183 SetLastError(0);
2184 src[0] = c;
2185 src[1] = dst[0] = '\0';
2186 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2187 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2189 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2190 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2191 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2192 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2193 strchrW(noDigitAvailable, c),
2194 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2195 ch, '0' + digitRanges[j] - ch, dst[0]);
2197 prev_ch = ch;
2200 /* MAP_FOLDCZONE */
2201 SetLastError(0);
2202 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2203 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2204 "Got %d, error %d\n", ret, GetLastError());
2205 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2206 "MAP_FOLDCZONE: Expanded incorrectly\n");
2208 /* MAP_EXPAND_LIGATURES */
2209 SetLastError(0);
2210 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2211 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2212 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2213 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2214 "Got %d, error %d\n", ret, GetLastError());
2215 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2216 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2219 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2224 #define LCID_OK(l) \
2225 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2226 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2227 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2228 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2229 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2231 static void test_ConvertDefaultLocale(void)
2233 LCID lcid;
2235 /* Doesn't change lcid, even if non default sublang/sort used */
2236 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2237 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2238 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2239 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2241 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2242 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2243 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2244 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2245 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2247 /* Invariant language is not treated specially */
2248 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2250 /* User/system default languages alone are not mapped */
2251 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2252 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2254 /* Default lcids */
2255 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2256 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2257 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2260 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2261 DWORD dwFlags, LONG_PTR lParam)
2263 trace("%08x, %s, %s, %08x, %08lx\n",
2264 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2266 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2267 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2269 /* If lParam is one, we are calling with flags defaulted from 0 */
2270 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2271 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2273 return TRUE;
2276 static void test_EnumSystemLanguageGroupsA(void)
2278 BOOL ret;
2280 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2282 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2283 return;
2286 /* No enumeration proc */
2287 SetLastError(0);
2288 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2289 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2291 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2292 return;
2294 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2295 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2297 /* Invalid flags */
2298 SetLastError(0);
2299 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2300 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2302 /* No flags - defaults to LGRPID_INSTALLED */
2303 SetLastError(0xdeadbeef);
2304 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2305 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2307 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2308 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2311 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2313 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2314 return TRUE;
2317 static void test_EnumSystemLocalesEx(void)
2319 BOOL ret;
2321 if (!pEnumSystemLocalesEx)
2323 win_skip( "EnumSystemLocalesEx not available\n" );
2324 return;
2326 SetLastError( 0xdeadbeef );
2327 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2328 ok( !ret, "should have failed\n" );
2329 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2330 SetLastError( 0xdeadbeef );
2331 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2332 ok( ret, "failed err %u\n", GetLastError() );
2335 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2336 LONG_PTR lParam)
2338 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2340 /* invalid locale enumerated on some platforms */
2341 if (lcid == 0)
2342 return TRUE;
2344 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2345 "Enumerated grp %d not valid\n", lgrpid);
2346 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2347 "Enumerated grp locale %d not valid\n", lcid);
2348 return TRUE;
2351 static void test_EnumLanguageGroupLocalesA(void)
2353 BOOL ret;
2355 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2357 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2358 return;
2361 /* No enumeration proc */
2362 SetLastError(0);
2363 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2364 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2366 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2367 return;
2369 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2370 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2372 /* lgrpid too small */
2373 SetLastError(0);
2374 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2375 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2376 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2378 /* lgrpid too big */
2379 SetLastError(0);
2380 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2381 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2382 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2384 /* dwFlags is reserved */
2385 SetLastError(0);
2386 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2387 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2388 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2390 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2393 static void test_SetLocaleInfoA(void)
2395 BOOL bRet;
2396 LCID lcid = GetUserDefaultLCID();
2398 /* Null data */
2399 SetLastError(0);
2400 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2401 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2402 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2404 /* IDATE */
2405 SetLastError(0);
2406 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2407 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2408 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2410 /* ILDATE */
2411 SetLastError(0);
2412 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2413 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2414 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2417 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2419 trace("%s %08lx\n", value, lParam);
2420 return(TRUE);
2423 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2425 ok(!enumCount, "callback called again unexpected\n");
2426 enumCount++;
2427 return(FALSE);
2430 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2432 ok(0,"callback called unexpected\n");
2433 return(FALSE);
2436 static void test_EnumUILanguageA(void)
2438 BOOL ret;
2439 if (!pEnumUILanguagesA) {
2440 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2441 return;
2444 SetLastError(ERROR_SUCCESS);
2445 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2446 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2448 win_skip("EnumUILanguagesA is not implemented\n");
2449 return;
2451 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2453 enumCount = 0;
2454 SetLastError(ERROR_SUCCESS);
2455 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2456 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2458 SetLastError(ERROR_SUCCESS);
2459 ret = pEnumUILanguagesA(NULL, 0, 0);
2460 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2461 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2462 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2464 SetLastError(ERROR_SUCCESS);
2465 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2466 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2467 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2469 SetLastError(ERROR_SUCCESS);
2470 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2471 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2472 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2473 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2476 static char date_fmt_buf[1024];
2478 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2480 lstrcatA(date_fmt_buf, fmt);
2481 lstrcatA(date_fmt_buf, "\n");
2482 return TRUE;
2485 static void test_EnumDateFormatsA(void)
2487 char *p, buf[256];
2488 BOOL ret;
2489 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2491 trace("EnumDateFormatsA 0\n");
2492 date_fmt_buf[0] = 0;
2493 SetLastError(0xdeadbeef);
2494 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2495 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2497 win_skip("0 for dwFlags is not supported\n");
2499 else
2501 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2502 trace("%s\n", date_fmt_buf);
2503 /* test the 1st enumerated format */
2504 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2505 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2506 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2507 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2510 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2511 date_fmt_buf[0] = 0;
2512 SetLastError(0xdeadbeef);
2513 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2514 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2516 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2518 else
2520 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2521 trace("%s\n", date_fmt_buf);
2522 /* test the 1st enumerated format */
2523 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2524 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2525 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2526 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2529 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2530 date_fmt_buf[0] = 0;
2531 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2532 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) 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);
2540 trace("EnumDateFormatsA DATE_LONGDATE\n");
2541 date_fmt_buf[0] = 0;
2542 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2543 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2544 trace("%s\n", date_fmt_buf);
2545 /* test the 1st enumerated format */
2546 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2547 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2548 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2549 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2551 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2552 date_fmt_buf[0] = 0;
2553 SetLastError(0xdeadbeef);
2554 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2555 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2557 skip("DATE_YEARMONTH is only present on W2K and later\n");
2558 return;
2560 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2561 trace("%s\n", date_fmt_buf);
2562 /* test the 1st enumerated format */
2563 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2564 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2565 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2566 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2567 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2570 static void test_EnumTimeFormatsA(void)
2572 char *p, buf[256];
2573 BOOL ret;
2574 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2576 trace("EnumTimeFormatsA 0\n");
2577 date_fmt_buf[0] = 0;
2578 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2579 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2580 trace("%s\n", date_fmt_buf);
2581 /* test the 1st enumerated format */
2582 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2583 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2584 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2585 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2587 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2588 date_fmt_buf[0] = 0;
2589 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2590 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2591 trace("%s\n", date_fmt_buf);
2592 /* test the 1st enumerated format */
2593 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2594 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2595 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2596 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2599 static void test_GetCPInfo(void)
2601 BOOL ret;
2602 CPINFO cpinfo;
2604 SetLastError(0xdeadbeef);
2605 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2606 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2607 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2608 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2610 SetLastError(0xdeadbeef);
2611 ret = GetCPInfo(CP_UTF7, &cpinfo);
2612 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2614 skip("Codepage CP_UTF7 is not installed/available\n");
2616 else
2618 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2619 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2620 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2621 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2622 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2623 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2626 SetLastError(0xdeadbeef);
2627 ret = GetCPInfo(CP_UTF8, &cpinfo);
2628 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2630 skip("Codepage CP_UTF8 is not installed/available\n");
2632 else
2634 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2635 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2636 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2637 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2638 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2639 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2640 "expected 4, got %u\n", cpinfo.MaxCharSize);
2645 * The CT_TYPE1 has varied over windows version.
2646 * The current target for correct behavior is windows 7.
2647 * There was a big shift between windows 2000 (first introduced) and windows Xp
2648 * Most of the old values below are from windows 2000.
2649 * A smaller subset of changes happened between windows Xp and Window vista/7
2651 static void test_GetStringTypeW(void)
2653 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2654 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2655 C1_SPACE | C1_BLANK | C1_DEFINED,
2656 C1_SPACE | C1_BLANK | C1_DEFINED,
2657 C1_SPACE | C1_BLANK | C1_DEFINED,
2658 C1_CNTRL | C1_BLANK | C1_DEFINED};
2659 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2660 C1_SPACE | C1_BLANK,
2661 C1_SPACE | C1_BLANK,
2662 C1_SPACE | C1_BLANK,
2663 C1_SPACE | C1_BLANK};
2665 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2667 /* Lu, Ll, Lt */
2668 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2669 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2670 C1_LOWER | C1_ALPHA,
2671 C1_UPPER | C1_LOWER | C1_ALPHA,
2672 C1_ALPHA};
2674 /* Sk, Sk, Mn, So, Me */
2675 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2676 /* Sc, Sm, No,*/
2677 0xffe0, 0xffe9, 0x2153};
2679 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2680 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2681 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2682 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2683 C1_ALPHA | C1_DEFINED,
2684 C1_CNTRL | C1_DEFINED,
2685 C1_PUNCT | C1_DEFINED,
2686 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2687 C1_ALPHA | C1_LOWER | C1_DEFINED,
2688 C1_ALPHA | C1_DEFINED };
2689 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2690 C1_ALPHA | C1_DEFINED,
2691 C1_CNTRL | C1_DEFINED,
2692 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2693 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2694 C1_ALPHA | C1_DEFINED,
2695 C1_DEFINED
2697 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2698 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2700 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2701 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2702 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2703 static const WCHAR lower_special[] = {0x2071, 0x207f};
2704 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2705 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2706 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2707 0xfff9, 0xfffa, 0xfffb};
2708 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2710 WORD types[20];
2711 int i;
2713 memset(types,0,sizeof(types));
2714 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2715 for (i = 0; i < 5; i++)
2716 ok(types[i] == blanks_new[i] || broken(types[i] == blanks_old[i] || broken(types[i] == 0)), "incorrect type1 returned for %x -> (%x != %x)\n",blanks[i],types[i],blanks_new[i]);
2718 memset(types,0,sizeof(types));
2719 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2720 for (i = 0; i < 3; i++)
2721 ok(types[i] == (C1_DEFINED | alpha_old[i]) || broken(types[i] == alpha_old[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",alpha[i], types[i],(C1_DEFINED | alpha_old[i]));
2722 memset(types,0,sizeof(types));
2723 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2724 for (i = 0; i < 5; i++)
2725 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2727 memset(types,0,sizeof(types));
2728 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2729 for (i = 0; i < 8; i++)
2730 ok(types[i] == C1_DEFINED || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",oldpunc[i], types[i], C1_DEFINED);
2732 memset(types,0,sizeof(types));
2733 GetStringTypeW(CT_CTYPE1, changed, 7, types);
2734 for (i = 0; i < 7; i++)
2735 ok(types[i] == changed_new[i] || broken(types[i] == changed_old[i]) || broken(types[i] == changed_xp[i]) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",changed[i], types[i], changed_new[i]);
2737 memset(types,0,sizeof(types));
2738 GetStringTypeW(CT_CTYPE1, punct, 7, types);
2739 for (i = 0; i < 7; i++)
2740 ok(types[i] == (C1_PUNCT | C1_DEFINED) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x != %x)\n",punct[i], types[i], (C1_PUNCT | C1_DEFINED));
2743 memset(types,0,sizeof(types));
2744 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
2745 for (i = 0; i < 12; i++)
2746 ok(types[i] & C1_PUNCT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have %x)\n",punct_special[i], types[i], C1_PUNCT);
2748 memset(types,0,sizeof(types));
2749 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
2750 for (i = 0; i < 3; i++)
2751 ok(types[i] & C1_DIGIT || broken(types[i] == 0), "incorrect types returned for %x -> (%x doest not have = %x)\n",digit_special[i], types[i], C1_DIGIT);
2753 memset(types,0,sizeof(types));
2754 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
2755 for (i = 0; i < 2; i++)
2756 ok(types[i] & C1_LOWER || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",lower_special[i], types[i], C1_LOWER);
2758 memset(types,0,sizeof(types));
2759 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
2760 for (i = 0; i < 20; i++)
2761 ok(types[i] & C1_CNTRL || broken(types[i] == (C1_BLANK|C1_SPACE)) || broken(types[i] == C1_PUNCT) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",cntrl_special[i], types[i], C1_CNTRL);
2763 memset(types,0,sizeof(types));
2764 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
2765 for (i = 0; i < 3; i++)
2766 ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
2769 START_TEST(locale)
2771 InitFunctionPointers();
2773 test_EnumTimeFormatsA();
2774 test_EnumDateFormatsA();
2775 test_GetLocaleInfoA();
2776 test_GetLocaleInfoW();
2777 test_GetTimeFormatA();
2778 test_GetDateFormatA();
2779 test_GetDateFormatW();
2780 test_GetCurrencyFormatA(); /* Also tests the W version */
2781 test_GetNumberFormatA(); /* Also tests the W version */
2782 test_CompareStringA();
2783 test_LCMapStringA();
2784 test_LCMapStringW();
2785 test_FoldStringA();
2786 test_FoldStringW();
2787 test_ConvertDefaultLocale();
2788 test_EnumSystemLanguageGroupsA();
2789 test_EnumSystemLocalesEx();
2790 test_EnumLanguageGroupLocalesA();
2791 test_SetLocaleInfoA();
2792 test_EnumUILanguageA();
2793 test_GetCPInfo();
2794 test_GetStringTypeW();
2795 /* this requires collation table patch to make it MS compatible */
2796 if (0) test_sorting();