kernel32/tests: Added more FoldString tests.
[wine/multimedia.git] / dlls / kernel32 / tests / locale.c
blob79653ba320c63093198c42a45743d44bc58a20b0
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 LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
75 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
76 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
77 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
78 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
80 static void InitFunctionPointers(void)
82 hKernel32 = GetModuleHandleA("kernel32");
83 pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
84 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
85 pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
86 pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
87 pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
88 pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
89 pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
90 pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
91 pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
94 #define eq(received, expected, label, type) \
95 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
96 (label), (received), (expected))
98 #define BUFFER_SIZE 128
99 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
101 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
102 #define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret)
103 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
104 "Expected '%s', got '%s'\n", Expected, buffer)
106 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
107 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
108 SetLastError(0xdeadbeef); buffer[0] = '\0'
109 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
110 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
112 #define NUO LOCALE_NOUSEROVERRIDE
114 static void test_GetLocaleInfoA(void)
116 int ret;
117 int len;
118 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
119 char buffer[BUFFER_SIZE];
120 char expected[BUFFER_SIZE];
122 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
124 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
125 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
126 assumes SUBLANG_NEUTRAL for zh */
127 memset(expected, 0, COUNTOF(expected));
128 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
129 SetLastError(0xdeadbeef);
130 memset(buffer, 0, COUNTOF(buffer));
131 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
132 ok((ret == len) && !lstrcmpA(buffer, expected),
133 "got %d with '%s' (expected %d with '%s')\n",
134 ret, buffer, len, expected);
136 memset(expected, 0, COUNTOF(expected));
137 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
138 if (len) {
139 SetLastError(0xdeadbeef);
140 memset(buffer, 0, COUNTOF(buffer));
141 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
142 ok((ret == len) && !lstrcmpA(buffer, expected),
143 "got %d with '%s' (expected %d with '%s')\n",
144 ret, buffer, len, expected);
146 else
147 win_skip("LANG_ARABIC not installed\n");
149 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
150 memset(expected, 0, COUNTOF(expected));
151 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
152 SetLastError(0xdeadbeef);
153 memset(buffer, 0, COUNTOF(buffer));
154 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
155 ok((ret == len) && !lstrcmpA(buffer, expected),
156 "got %d with '%s' (expected %d with '%s')\n",
157 ret, buffer, len, expected);
160 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
161 * partially fill the buffer even if it is too short. See bug 637.
163 SetLastError(0xdeadbeef);
164 memset(buffer, 0, COUNTOF(buffer));
165 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
166 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
168 SetLastError(0xdeadbeef);
169 memset(buffer, 0, COUNTOF(buffer));
170 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
171 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
172 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
173 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
175 SetLastError(0xdeadbeef);
176 memset(buffer, 0, COUNTOF(buffer));
177 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
178 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
179 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
182 static void test_GetLocaleInfoW(void)
184 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
185 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
186 WCHAR bufferW[80], buffer2W[80];
187 CHAR bufferA[80];
188 DWORD ret;
189 INT i;
191 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
192 if (!ret) {
193 win_skip("GetLocaleInfoW() isn't implemented\n");
194 return;
196 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
197 if (!ret) {
198 win_skip("LANG_RUSSIAN locale data unavailable\n");
199 return;
201 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
202 bufferW, COUNTOF(bufferW));
203 if (!ret) {
204 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
205 return;
208 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
209 bufferA[0] = 'a';
210 SetLastError(0xdeadbeef);
211 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
212 bufferA, COUNTOF(bufferA));
213 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
214 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
215 ok(GetLastError() == ERROR_INVALID_FLAGS,
216 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
218 bufferW[0] = 'a';
219 SetLastError(0xdeadbeef);
220 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
221 bufferW, COUNTOF(bufferW));
222 ok(ret == 0,
223 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
224 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
225 ok(GetLastError() == ERROR_INVALID_FLAGS,
226 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
228 /* yes, test empty 13 month entry too */
229 for (i = 0; i < 12; i++) {
230 bufferW[0] = 0;
231 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
232 bufferW, COUNTOF(bufferW));
233 ok(ret, "Expected non zero result\n");
234 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
235 ret, lstrlenW(bufferW));
236 buffer2W[0] = 0;
237 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
238 buffer2W, COUNTOF(buffer2W));
239 ok(ret, "Expected non zero result\n");
240 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
241 ret, lstrlenW(buffer2W));
243 ok(lstrcmpW(bufferW, buffer2W) != 0,
244 "Expected genitive name to differ, got the same for month %d\n", i+1);
246 /* for locale without genitive names nominative returned in both cases */
247 bufferW[0] = 0;
248 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
249 bufferW, COUNTOF(bufferW));
250 ok(ret, "Expected non zero result\n");
251 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
252 ret, lstrlenW(bufferW));
253 buffer2W[0] = 0;
254 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
255 buffer2W, COUNTOF(buffer2W));
256 ok(ret, "Expected non zero result\n");
257 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
258 ret, lstrlenW(buffer2W));
260 ok(lstrcmpW(bufferW, buffer2W) == 0,
261 "Expected same names, got different for month %d\n", i+1);
265 static void test_GetTimeFormatA(void)
267 int ret;
268 SYSTEMTIME curtime;
269 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
270 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
272 memset(&curtime, 2, sizeof(SYSTEMTIME));
273 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
274 SetLastError(0xdeadbeef);
275 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
276 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
277 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
279 curtime.wHour = 8;
280 curtime.wMinute = 56;
281 curtime.wSecond = 13;
282 curtime.wMilliseconds = 22;
283 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
284 SetLastError(0xdeadbeef);
285 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
286 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
287 EXPECT_LENA; EXPECT_EQA;
289 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
290 SetLastError(0xdeadbeef);
291 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
292 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
293 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
295 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
296 SetLastError(0xdeadbeef);
297 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
298 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
299 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
301 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
302 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
303 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
304 EXPECT_LENA;
306 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
307 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
308 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
309 EXPECT_LENA; EXPECT_EQA;
311 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
312 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
313 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
314 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
315 "Expected '', got '%s'\n", buffer );
317 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
318 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
319 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
320 EXPECT_LENA; EXPECT_EQA;
322 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
323 strcpy(Expected, "8:56 AM");
324 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
326 EXPECT_LENA; EXPECT_EQA;
328 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
329 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
330 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
331 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
332 "Expected '8.@:56AM', got '%s'\n", buffer );
334 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
335 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
336 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
337 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
338 "Expected '', got '%s'\n", buffer );
340 STRINGSA("t/tt", "A/AM"); /* AM time marker */
341 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
342 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
343 EXPECT_LENA; EXPECT_EQA;
345 curtime.wHour = 13;
346 STRINGSA("t/tt", "P/PM"); /* PM time marker */
347 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
348 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
349 EXPECT_LENA; EXPECT_EQA;
351 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
352 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
353 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
354 EXPECT_LENA; EXPECT_EQA;
356 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
357 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
358 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
359 EXPECT_LENA; EXPECT_EQA;
361 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
362 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
363 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
364 EXPECT_LENA; EXPECT_EQA;
366 curtime.wHour = 14; /* change this to 14 or 2pm */
367 curtime.wMinute = 5;
368 curtime.wSecond = 3;
369 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 */
370 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
371 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
372 EXPECT_LENA; EXPECT_EQA;
374 curtime.wHour = 0;
375 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
376 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
377 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
378 EXPECT_LENA; EXPECT_EQA;
380 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
381 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
382 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
383 EXPECT_LENA; EXPECT_EQA;
385 /* try to convert formatting strings with more than two letters
386 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
387 * NOTE: We expect any letter for which there is an upper case value
388 * we should see a replacement. For letters that DO NOT have
389 * upper case values we should see NO REPLACEMENT.
391 curtime.wHour = 8;
392 curtime.wMinute = 56;
393 curtime.wSecond = 13;
394 curtime.wMilliseconds = 22;
395 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
396 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
397 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
398 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
399 EXPECT_LENA; EXPECT_EQA;
401 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
402 strcpy(buffer, "text");
403 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
404 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
405 EXPECT_EQA;
407 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
408 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
409 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
410 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
411 EXPECT_LENA; EXPECT_EQA;
413 STRINGSA("'''", "'"); /* invalid quoted string */
414 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
415 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
416 EXPECT_LENA; EXPECT_EQA;
418 /* test that msdn suggested single quotation usage works as expected */
419 STRINGSA("''''", "'"); /* single quote mark */
420 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
421 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
422 EXPECT_LENA; EXPECT_EQA;
424 STRINGSA("''HHHHHH", "08"); /* Normal use */
425 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
426 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
427 EXPECT_LENA; EXPECT_EQA;
429 /* and test for normal use of the single quotation mark */
430 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
431 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
432 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
433 EXPECT_LENA; EXPECT_EQA;
435 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
436 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
437 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
438 EXPECT_LENA; EXPECT_EQA;
440 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
441 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
442 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
443 EXPECT_LENA; EXPECT_EQA;
445 curtime.wHour = 25;
446 STRINGSA("'123'tt", ""); /* Invalid time */
447 SetLastError(0xdeadbeef);
448 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
449 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
450 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
452 curtime.wHour = 12;
453 curtime.wMonth = 60; /* Invalid */
454 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
455 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
456 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
457 EXPECT_LENA; EXPECT_EQA;
460 static void test_GetDateFormatA(void)
462 int ret;
463 SYSTEMTIME curtime;
464 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
465 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
466 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
467 char Broken[BUFFER_SIZE];
468 char short_day[10], month[10], genitive_month[10];
470 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
471 STRINGSA("ddd',' MMM dd yy","");
472 SetLastError(0xdeadbeef);
473 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
474 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
475 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
477 curtime.wYear = 2002;
478 curtime.wMonth = 5;
479 curtime.wDay = 4;
480 curtime.wDayOfWeek = 3;
481 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
482 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
483 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
484 EXPECT_LENA; EXPECT_EQA;
486 /* Same as above but with LOCALE_NOUSEROVERRIDE */
487 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
488 SetLastError(0xdeadbeef);
489 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
490 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
491 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
492 EXPECT_EQA;
494 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
495 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
496 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
497 EXPECT_LENA; EXPECT_EQA;
499 curtime.wHour = 36; /* Invalid */
500 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
501 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
503 EXPECT_LENA; EXPECT_EQA;
505 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
506 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
507 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
508 EXPECT_EQA;
510 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
511 SetLastError(0xdeadbeef);
512 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
513 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
514 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
516 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
517 ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
518 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
519 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
520 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
522 STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */
523 ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
525 EXPECT_LENA; EXPECT_EQA;
527 /* test for expected DATE_YEARMONTH behavior with null format */
528 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
529 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
530 SetLastError(0xdeadbeef);
531 ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
532 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
533 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
534 EXPECT_EQA;
536 /* Test that using invalid DATE_* flags results in the correct error */
537 /* and return values */
538 STRINGSA("m/d/y", ""); /* Invalid flags */
539 SetLastError(0xdeadbeef);
540 ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
541 &curtime, input, buffer, COUNTOF(buffer));
542 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
543 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
545 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
546 if (!ret)
548 win_skip("LANG_RUSSIAN locale data unavailable\n");
549 return;
552 /* month part should be in genitive form */
553 strcpy(genitive_month, buffer + 2);
554 ret = GetDateFormat(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
555 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
556 strcpy(month, buffer);
557 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
559 ret = GetDateFormat(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
561 strcpy(short_day, buffer);
563 STRINGSA("dd MMMMddd dd", "");
564 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
565 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
567 EXPECT_EQA;
569 STRINGSA("MMMMddd dd", "");
570 sprintf(Expected, "%s%s 04", month, short_day);
571 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
573 EXPECT_EQA;
575 STRINGSA("MMMMddd", "");
576 sprintf(Expected, "%s%s", month, short_day);
577 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
579 EXPECT_EQA;
581 STRINGSA("MMMMdd", "");
582 sprintf(Expected, "%s04", genitive_month);
583 sprintf(Broken, "%s04", month);
584 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
585 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
586 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
587 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
588 "Expected '%s', got '%s'\n", Expected, buffer);
590 STRINGSA("MMMMdd ddd", "");
591 sprintf(Expected, "%s04 %s", genitive_month, short_day);
592 sprintf(Broken, "%s04 %s", month, short_day);
593 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
595 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
596 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
597 "Expected '%s', got '%s'\n", Expected, buffer);
599 STRINGSA("dd dddMMMM", "");
600 sprintf(Expected, "04 %s%s", short_day, month);
601 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
602 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
603 EXPECT_EQA;
605 STRINGSA("dd dddMMMM ddd MMMMdd", "");
606 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
607 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
608 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
609 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
610 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
611 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
612 "Expected '%s', got '%s'\n", Expected, buffer);
614 /* with literal part */
615 STRINGSA("ddd',' MMMM dd", "");
616 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
617 sprintf(Broken, "%s, %s 04", short_day, month);
618 ret = GetDateFormat(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
619 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
620 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
621 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
622 "Expected '%s', got '%s'\n", Expected, buffer);
625 static void test_GetDateFormatW(void)
627 int ret;
628 SYSTEMTIME curtime;
629 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
630 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
632 STRINGSW("",""); /* If flags is not zero then format must be NULL */
633 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
634 input, buffer, COUNTOF(buffer));
635 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
637 win_skip("GetDateFormatW is not implemented\n");
638 return;
640 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
641 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
642 EXPECT_EQW;
644 STRINGSW("",""); /* NULL buffer, len > 0 */
645 SetLastError(0xdeadbeef);
646 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
647 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
648 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
650 STRINGSW("",""); /* NULL buffer, len == 0 */
651 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
652 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
653 EXPECT_LENW; EXPECT_EQW;
655 curtime.wYear = 2002;
656 curtime.wMonth = 10;
657 curtime.wDay = 23;
658 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
659 curtime.wHour = 65432; /* Invalid */
660 curtime.wMinute = 34512; /* Invalid */
661 curtime.wSecond = 65535; /* Invalid */
662 curtime.wMilliseconds = 12345;
663 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
664 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
665 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
666 EXPECT_LENW; EXPECT_EQW;
668 /* Limit tests */
670 curtime.wYear = 1601;
671 curtime.wMonth = 1;
672 curtime.wDay = 1;
673 curtime.wDayOfWeek = 0; /* Irrelevant */
674 curtime.wHour = 0;
675 curtime.wMinute = 0;
676 curtime.wSecond = 0;
677 curtime.wMilliseconds = 0;
678 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
679 SetLastError(0xdeadbeef);
680 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
682 EXPECT_LENW; EXPECT_EQW;
684 curtime.wYear = 1600;
685 curtime.wMonth = 12;
686 curtime.wDay = 31;
687 curtime.wDayOfWeek = 0; /* Irrelevant */
688 curtime.wHour = 23;
689 curtime.wMinute = 59;
690 curtime.wSecond = 59;
691 curtime.wMilliseconds = 999;
692 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
693 SetLastError(0xdeadbeef);
694 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
695 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
696 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
700 #define CY_POS_LEFT 0
701 #define CY_POS_RIGHT 1
702 #define CY_POS_LEFT_SPACE 2
703 #define CY_POS_RIGHT_SPACE 3
705 static void test_GetCurrencyFormatA(void)
707 static char szDot[] = { '.', '\0' };
708 static char szComma[] = { ',', '\0' };
709 static char szDollar[] = { '$', '\0' };
710 int ret;
711 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
712 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
713 CURRENCYFMTA format;
715 memset(&format, 0, sizeof(format));
717 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
718 SetLastError(0xdeadbeef);
719 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
720 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
721 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
723 STRINGSA("23,53",""); /* Invalid character --> Error */
724 SetLastError(0xdeadbeef);
725 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
726 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
727 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
729 STRINGSA("--",""); /* Double '-' --> Error */
730 SetLastError(0xdeadbeef);
731 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
732 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
733 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
735 STRINGSA("0-",""); /* Trailing '-' --> Error */
736 SetLastError(0xdeadbeef);
737 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
738 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
739 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
741 STRINGSA("0..",""); /* Double '.' --> Error */
742 SetLastError(0xdeadbeef);
743 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
744 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
745 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
747 STRINGSA(" 0.1",""); /* Leading space --> Error */
748 SetLastError(0xdeadbeef);
749 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
750 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
751 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
753 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
754 SetLastError(0xdeadbeef);
755 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
756 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
757 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
759 STRINGSA("2353",""); /* Format and flags given --> Error */
760 SetLastError(0xdeadbeef);
761 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
762 ok( !ret, "Expected ret == 0, got %d\n", ret);
763 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
764 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
766 STRINGSA("2353",""); /* Invalid format --> Error */
767 SetLastError(0xdeadbeef);
768 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
769 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
770 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
772 STRINGSA("2353","$2,353.00"); /* Valid number */
773 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
774 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
775 EXPECT_LENA; EXPECT_EQA;
777 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
778 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
779 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
780 EXPECT_LENA; EXPECT_EQA;
782 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
783 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
784 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
785 EXPECT_LENA; EXPECT_EQA;
787 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
788 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
789 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
790 EXPECT_LENA; EXPECT_EQA;
792 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
793 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
794 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
795 EXPECT_LENA; EXPECT_EQA;
797 format.NumDigits = 0; /* No decimal separator */
798 format.LeadingZero = 0;
799 format.Grouping = 0; /* No grouping char */
800 format.NegativeOrder = 0;
801 format.PositiveOrder = CY_POS_LEFT;
802 format.lpDecimalSep = szDot;
803 format.lpThousandSep = szComma;
804 format.lpCurrencySymbol = szDollar;
806 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
807 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
808 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
809 EXPECT_LENA; EXPECT_EQA;
811 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
812 STRINGSA("2353","$2353.0");
813 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
814 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
815 EXPECT_LENA; EXPECT_EQA;
817 format.Grouping = 2; /* Group by 100's */
818 STRINGSA("2353","$23,53.0");
819 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
820 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
821 EXPECT_LENA; EXPECT_EQA;
823 STRINGSA("235","$235.0"); /* Grouping of a positive number */
824 format.Grouping = 3;
825 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
826 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
827 EXPECT_LENA; EXPECT_EQA;
829 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
830 format.NegativeOrder = 2;
831 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
832 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
833 EXPECT_LENA; EXPECT_EQA;
835 format.LeadingZero = 1; /* Always provide leading zero */
836 STRINGSA(".5","$0.5");
837 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
838 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
839 EXPECT_LENA; EXPECT_EQA;
841 format.PositiveOrder = CY_POS_RIGHT;
842 STRINGSA("1","1.0$");
843 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
844 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
845 EXPECT_LENA; EXPECT_EQA;
847 format.PositiveOrder = CY_POS_LEFT_SPACE;
848 STRINGSA("1","$ 1.0");
849 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
850 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
851 EXPECT_LENA; EXPECT_EQA;
853 format.PositiveOrder = CY_POS_RIGHT_SPACE;
854 STRINGSA("1","1.0 $");
855 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
856 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
857 EXPECT_LENA; EXPECT_EQA;
859 format.NegativeOrder = 0;
860 STRINGSA("-1","($1.0)");
861 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
862 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
863 EXPECT_LENA; EXPECT_EQA;
865 format.NegativeOrder = 1;
866 STRINGSA("-1","-$1.0");
867 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
868 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
869 EXPECT_LENA; EXPECT_EQA;
871 format.NegativeOrder = 2;
872 STRINGSA("-1","$-1.0");
873 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
874 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
875 EXPECT_LENA; EXPECT_EQA;
877 format.NegativeOrder = 3;
878 STRINGSA("-1","$1.0-");
879 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
880 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
881 EXPECT_LENA; EXPECT_EQA;
883 format.NegativeOrder = 4;
884 STRINGSA("-1","(1.0$)");
885 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
886 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
887 EXPECT_LENA; EXPECT_EQA;
889 format.NegativeOrder = 5;
890 STRINGSA("-1","-1.0$");
891 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
892 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
893 EXPECT_LENA; EXPECT_EQA;
895 format.NegativeOrder = 6;
896 STRINGSA("-1","1.0-$");
897 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
898 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
899 EXPECT_LENA; EXPECT_EQA;
901 format.NegativeOrder = 7;
902 STRINGSA("-1","1.0$-");
903 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
904 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
905 EXPECT_LENA; EXPECT_EQA;
907 format.NegativeOrder = 8;
908 STRINGSA("-1","-1.0 $");
909 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
910 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
911 EXPECT_LENA; EXPECT_EQA;
913 format.NegativeOrder = 9;
914 STRINGSA("-1","-$ 1.0");
915 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 EXPECT_LENA; EXPECT_EQA;
919 format.NegativeOrder = 10;
920 STRINGSA("-1","1.0 $-");
921 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
922 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
923 EXPECT_LENA; EXPECT_EQA;
925 format.NegativeOrder = 11;
926 STRINGSA("-1","$ 1.0-");
927 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
928 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
929 EXPECT_LENA; EXPECT_EQA;
931 format.NegativeOrder = 12;
932 STRINGSA("-1","$ -1.0");
933 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
934 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
935 EXPECT_LENA; EXPECT_EQA;
937 format.NegativeOrder = 13;
938 STRINGSA("-1","1.0- $");
939 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
940 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
941 EXPECT_LENA; EXPECT_EQA;
943 format.NegativeOrder = 14;
944 STRINGSA("-1","($ 1.0)");
945 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 EXPECT_LENA; EXPECT_EQA;
949 format.NegativeOrder = 15;
950 STRINGSA("-1","(1.0 $)");
951 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
952 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
953 EXPECT_LENA; EXPECT_EQA;
956 #define NEG_PARENS 0 /* "(1.1)" */
957 #define NEG_LEFT 1 /* "-1.1" */
958 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
959 #define NEG_RIGHT 3 /* "1.1-" */
960 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
962 static void test_GetNumberFormatA(void)
964 static char szDot[] = { '.', '\0' };
965 static char szComma[] = { ',', '\0' };
966 int ret;
967 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
968 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
969 NUMBERFMTA format;
971 memset(&format, 0, sizeof(format));
973 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
974 SetLastError(0xdeadbeef);
975 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
976 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
977 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
979 STRINGSA("23,53",""); /* Invalid character --> Error */
980 SetLastError(0xdeadbeef);
981 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
982 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
983 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
985 STRINGSA("--",""); /* Double '-' --> Error */
986 SetLastError(0xdeadbeef);
987 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
988 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
989 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
991 STRINGSA("0-",""); /* Trailing '-' --> Error */
992 SetLastError(0xdeadbeef);
993 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
994 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
995 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
997 STRINGSA("0..",""); /* Double '.' --> Error */
998 SetLastError(0xdeadbeef);
999 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1000 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1001 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1003 STRINGSA(" 0.1",""); /* Leading space --> Error */
1004 SetLastError(0xdeadbeef);
1005 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1006 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1007 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1009 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1010 SetLastError(0xdeadbeef);
1011 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1012 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1013 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1015 STRINGSA("2353",""); /* Format and flags given --> Error */
1016 SetLastError(0xdeadbeef);
1017 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1018 ok( !ret, "Expected ret == 0, got %d\n", ret);
1019 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1020 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1022 STRINGSA("2353",""); /* Invalid format --> Error */
1023 SetLastError(0xdeadbeef);
1024 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1025 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1026 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1028 STRINGSA("2353","2,353.00"); /* Valid number */
1029 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1030 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1031 EXPECT_LENA; EXPECT_EQA;
1033 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1034 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1036 EXPECT_LENA; EXPECT_EQA;
1038 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1039 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1040 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1041 EXPECT_LENA; EXPECT_EQA;
1043 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1044 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1045 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1046 EXPECT_LENA; EXPECT_EQA;
1048 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1049 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1050 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1051 EXPECT_LENA; EXPECT_EQA;
1053 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1054 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1055 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1056 EXPECT_LENA; EXPECT_EQA;
1058 format.NumDigits = 0; /* No decimal separator */
1059 format.LeadingZero = 0;
1060 format.Grouping = 0; /* No grouping char */
1061 format.NegativeOrder = 0;
1062 format.lpDecimalSep = szDot;
1063 format.lpThousandSep = szComma;
1065 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1066 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1067 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1068 EXPECT_LENA; EXPECT_EQA;
1070 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1071 STRINGSA("2353","2353.0");
1072 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1073 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1074 EXPECT_LENA; EXPECT_EQA;
1076 format.Grouping = 2; /* Group by 100's */
1077 STRINGSA("2353","23,53.0");
1078 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1079 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1080 EXPECT_LENA; EXPECT_EQA;
1082 STRINGSA("235","235.0"); /* Grouping of a positive number */
1083 format.Grouping = 3;
1084 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1085 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1086 EXPECT_LENA; EXPECT_EQA;
1088 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1089 format.NegativeOrder = NEG_LEFT;
1090 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1091 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1092 EXPECT_LENA; EXPECT_EQA;
1094 format.LeadingZero = 1; /* Always provide leading zero */
1095 STRINGSA(".5","0.5");
1096 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1097 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1098 EXPECT_LENA; EXPECT_EQA;
1100 format.NegativeOrder = NEG_PARENS;
1101 STRINGSA("-1","(1.0)");
1102 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1103 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1104 EXPECT_LENA; EXPECT_EQA;
1106 format.NegativeOrder = NEG_LEFT;
1107 STRINGSA("-1","-1.0");
1108 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENA; EXPECT_EQA;
1112 format.NegativeOrder = NEG_LEFT_SPACE;
1113 STRINGSA("-1","- 1.0");
1114 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1115 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1116 EXPECT_LENA; EXPECT_EQA;
1118 format.NegativeOrder = NEG_RIGHT;
1119 STRINGSA("-1","1.0-");
1120 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1121 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1122 EXPECT_LENA; EXPECT_EQA;
1124 format.NegativeOrder = NEG_RIGHT_SPACE;
1125 STRINGSA("-1","1.0 -");
1126 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1127 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1128 EXPECT_LENA; EXPECT_EQA;
1130 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1132 if (IsValidLocale(lcid, 0))
1134 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1135 Expected[3] = 160; /* Non breaking space */
1136 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1137 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1138 EXPECT_LENA; EXPECT_EQA;
1142 struct comparestringa_entry {
1143 LCID lcid;
1144 DWORD flags;
1145 const char *first;
1146 int first_len;
1147 const char *second;
1148 int second_len;
1149 int ret;
1152 static const struct comparestringa_entry comparestringa_data[] = {
1153 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1154 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1155 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1156 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1157 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1158 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1159 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1160 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1161 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1162 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1163 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1164 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1165 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1166 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1167 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1168 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1169 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1170 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1171 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1172 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
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, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1178 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1179 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1180 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1181 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1182 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
1185 static void test_CompareStringA(void)
1187 int ret, i;
1188 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1190 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1192 const struct comparestringa_entry *entry = &comparestringa_data[i];
1194 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1195 entry->second, entry->second_len);
1196 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1199 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1200 ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
1202 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1203 ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret);
1205 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1206 ok (ret== 3, "(Salut/hola) Expected 3, got %d\n", ret);
1208 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1209 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1211 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1213 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1214 ok (ret== 1, "(haha/hoho) Expected 1, got %d\n", ret);
1216 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1217 ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
1219 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1220 ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
1222 /* test for CompareStringA flags */
1223 SetLastError(0xdeadbeef);
1224 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1225 ok(GetLastError() == ERROR_INVALID_FLAGS,
1226 "unexpected error code %d\n", GetLastError());
1227 ok(!ret, "CompareStringA must fail with invalid flag\n");
1229 SetLastError(0xdeadbeef);
1230 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1231 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1232 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1233 /* end of test for CompareStringA flags */
1235 ret = lstrcmpA("", "");
1236 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1238 ret = lstrcmpA(NULL, NULL);
1239 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1241 ret = lstrcmpA("", NULL);
1242 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1244 ret = lstrcmpA(NULL, "");
1245 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1248 if (0) { /* this requires collation table patch to make it MS compatible */
1249 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1250 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1252 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1253 ok(ret == 1, "'o vs -o expected 1, got %d\n", ret);
1255 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1256 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1258 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1259 ok(ret == 1, "' vs - expected 1, got %d\n", ret);
1261 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1262 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1264 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1265 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1267 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1268 ok(ret == 3, "`o vs /m expected 3, got %d\n", ret);
1270 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1271 ok(ret == 1, "/m vs `o expected 1, got %d\n", ret);
1273 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1274 ok(ret == 1, "`o vs -m expected 1, got %d\n", ret);
1276 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1277 ok(ret == 3, "-m vs `o expected 3, got %d\n", ret);
1279 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1280 ok(ret == 3, "`o vs -m expected 3, got %d\n", ret);
1282 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1283 ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
1287 /* WinXP handles embedded NULLs differently than earlier versions */
1288 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1289 ok(ret == 1 || ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1291 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1292 ok(ret == 1 || ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 1 or 2, got %d\n", ret);
1294 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1295 ok(ret == 2, "a vs a expected 2, got %d\n", ret);
1297 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1298 ok(ret == CSTR_EQUAL || /* win2k */
1299 ret == CSTR_GREATER_THAN,
1300 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1302 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1303 todo_wine ok(ret != 2, "\\2 vs \\1 expected unequal\n");
1305 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1306 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1308 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1309 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1311 ret = lstrcmpi("#", ".");
1312 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1314 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1316 /* \xB9 character lies between a and b */
1317 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1318 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1319 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1320 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1323 static void test_LCMapStringA(void)
1325 int ret, ret2;
1326 char buf[256], buf2[256];
1327 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
1328 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
1329 static const char symbols_stripped[] = "justateststring1";
1331 SetLastError(0xdeadbeef);
1332 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
1333 lower_case, -1, buf, sizeof(buf));
1334 ok(ret == lstrlenA(lower_case) + 1,
1335 "ret %d, error %d, expected value %d\n",
1336 ret, GetLastError(), lstrlenA(lower_case) + 1);
1337 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1339 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1340 upper_case, -1, buf, sizeof(buf));
1341 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1342 ok(GetLastError() == ERROR_INVALID_FLAGS,
1343 "unexpected error code %d\n", GetLastError());
1345 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1346 upper_case, -1, buf, sizeof(buf));
1347 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1348 ok(GetLastError() == ERROR_INVALID_FLAGS,
1349 "unexpected error code %d\n", GetLastError());
1351 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1352 upper_case, -1, buf, sizeof(buf));
1353 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1354 ok(GetLastError() == ERROR_INVALID_FLAGS,
1355 "unexpected error code %d\n", GetLastError());
1357 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1358 upper_case, -1, buf, sizeof(buf));
1359 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1360 ok(GetLastError() == ERROR_INVALID_FLAGS,
1361 "unexpected error code %d\n", GetLastError());
1363 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1364 SetLastError(0xdeadbeef);
1365 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1366 upper_case, -1, buf, sizeof(buf));
1367 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1368 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1370 /* test LCMAP_LOWERCASE */
1371 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1372 upper_case, -1, buf, sizeof(buf));
1373 ok(ret == lstrlenA(upper_case) + 1,
1374 "ret %d, error %d, expected value %d\n",
1375 ret, GetLastError(), lstrlenA(upper_case) + 1);
1376 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1378 /* test LCMAP_UPPERCASE */
1379 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1380 lower_case, -1, buf, sizeof(buf));
1381 ok(ret == lstrlenA(lower_case) + 1,
1382 "ret %d, error %d, expected value %d\n",
1383 ret, GetLastError(), lstrlenA(lower_case) + 1);
1384 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1386 /* test buffer overflow */
1387 SetLastError(0xdeadbeef);
1388 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1389 lower_case, -1, buf, 4);
1390 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1391 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1393 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1394 lstrcpyA(buf, lower_case);
1395 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1396 buf, -1, buf, sizeof(buf));
1397 if (!ret) /* Win9x */
1398 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
1399 else
1401 ok(ret == lstrlenA(lower_case) + 1,
1402 "ret %d, error %d, expected value %d\n",
1403 ret, GetLastError(), lstrlenA(lower_case) + 1);
1404 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
1406 lstrcpyA(buf, upper_case);
1407 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1408 buf, -1, buf, sizeof(buf));
1409 if (!ret) /* Win9x */
1410 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
1411 else
1413 ok(ret == lstrlenA(upper_case) + 1,
1414 "ret %d, error %d, expected value %d\n",
1415 ret, GetLastError(), lstrlenA(lower_case) + 1);
1416 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1419 /* otherwise src == dst should fail */
1420 SetLastError(0xdeadbeef);
1421 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1422 buf, 10, buf, sizeof(buf));
1423 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1424 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1425 "unexpected error code %d\n", GetLastError());
1426 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1428 /* test whether '\0' is always appended */
1429 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1430 upper_case, -1, buf, sizeof(buf));
1431 ok(ret, "LCMapStringA must succeed\n");
1432 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
1433 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1434 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
1435 ok(ret2, "LCMapStringA must succeed\n");
1436 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
1437 ok(ret == ret2, "lengths of sort keys must be equal\n");
1438 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1440 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1441 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1442 upper_case, -1, buf, sizeof(buf));
1443 ok(ret, "LCMapStringA must succeed\n");
1444 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1445 lower_case, -1, buf2, sizeof(buf2));
1446 ok(ret2, "LCMapStringA must succeed\n");
1447 ok(ret == ret2, "lengths of sort keys must be equal\n");
1448 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1450 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1451 results from plain LCMAP_SORTKEY on Vista */
1453 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1454 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1455 lower_case, -1, buf, sizeof(buf));
1456 ok(ret, "LCMapStringA must succeed\n");
1457 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1458 symbols_stripped, -1, buf2, sizeof(buf2));
1459 ok(ret2, "LCMapStringA must succeed\n");
1460 ok(ret == ret2, "lengths of sort keys must be equal\n");
1461 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
1463 /* test NORM_IGNORENONSPACE */
1464 lstrcpyA(buf, "foo");
1465 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1466 lower_case, -1, buf, sizeof(buf));
1467 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
1468 lstrlenA(lower_case) + 1, ret);
1469 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1471 /* test NORM_IGNORESYMBOLS */
1472 lstrcpyA(buf, "foo");
1473 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1474 lower_case, -1, buf, sizeof(buf));
1475 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
1476 lstrlenA(symbols_stripped) + 1, ret);
1477 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
1479 /* test srclen = 0 */
1480 SetLastError(0xdeadbeef);
1481 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
1482 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
1483 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1484 "unexpected error code %d\n", GetLastError());
1487 static void test_LCMapStringW(void)
1489 int ret, ret2;
1490 WCHAR buf[256], buf2[256];
1491 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
1492 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};
1493 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};
1494 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
1495 static const WCHAR fooW[] = {'f','o','o',0};
1497 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
1498 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1499 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1501 win_skip("LCMapStringW is not implemented\n");
1502 return;
1504 if (broken(ret))
1505 ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
1506 else
1508 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
1509 ok(GetLastError() == ERROR_INVALID_FLAGS,
1510 "unexpected error code %d\n", GetLastError());
1513 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
1514 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1515 ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
1516 ok(GetLastError() == ERROR_INVALID_FLAGS,
1517 "unexpected error code %d\n", GetLastError());
1519 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
1520 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1521 ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
1522 ok(GetLastError() == ERROR_INVALID_FLAGS,
1523 "unexpected error code %d\n", GetLastError());
1525 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
1526 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1527 ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
1528 ok(GetLastError() == ERROR_INVALID_FLAGS,
1529 "unexpected error code %d\n", GetLastError());
1531 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
1532 SetLastError(0xdeadbeef);
1533 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
1534 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1535 ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1536 ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
1538 /* test LCMAP_LOWERCASE */
1539 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1540 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1541 ok(ret == lstrlenW(upper_case) + 1,
1542 "ret %d, error %d, expected value %d\n",
1543 ret, GetLastError(), lstrlenW(upper_case) + 1);
1544 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1546 /* test LCMAP_UPPERCASE */
1547 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1548 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1549 ok(ret == lstrlenW(lower_case) + 1,
1550 "ret %d, error %d, expected value %d\n",
1551 ret, GetLastError(), lstrlenW(lower_case) + 1);
1552 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1554 /* test buffer overflow */
1555 SetLastError(0xdeadbeef);
1556 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1557 lower_case, -1, buf, 4);
1558 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1559 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
1561 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
1562 lstrcpyW(buf, lower_case);
1563 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
1564 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1565 ok(ret == lstrlenW(lower_case) + 1,
1566 "ret %d, error %d, expected value %d\n",
1567 ret, GetLastError(), lstrlenW(lower_case) + 1);
1568 ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
1570 lstrcpyW(buf, upper_case);
1571 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
1572 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
1573 ok(ret == lstrlenW(upper_case) + 1,
1574 "ret %d, error %d, expected value %d\n",
1575 ret, GetLastError(), lstrlenW(lower_case) + 1);
1576 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
1578 /* otherwise src == dst should fail */
1579 SetLastError(0xdeadbeef);
1580 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
1581 buf, 10, buf, sizeof(buf));
1582 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
1583 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
1584 "unexpected error code %d\n", GetLastError());
1585 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
1587 /* test whether '\0' is always appended */
1588 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1589 upper_case, -1, buf, sizeof(buf));
1590 ok(ret, "LCMapStringW must succeed\n");
1591 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1592 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
1593 ok(ret, "LCMapStringW must succeed\n");
1594 ok(ret == ret2, "lengths of sort keys must be equal\n");
1595 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1597 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
1598 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
1599 upper_case, -1, buf, sizeof(buf));
1600 ok(ret, "LCMapStringW must succeed\n");
1601 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1602 lower_case, -1, buf2, sizeof(buf2));
1603 ok(ret2, "LCMapStringW must succeed\n");
1604 ok(ret == ret2, "lengths of sort keys must be equal\n");
1605 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1607 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
1608 results from plain LCMAP_SORTKEY on Vista */
1610 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
1611 ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
1612 lower_case, -1, buf, sizeof(buf));
1613 ok(ret, "LCMapStringW must succeed\n");
1614 ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
1615 symbols_stripped, -1, buf2, sizeof(buf2));
1616 ok(ret2, "LCMapStringW must succeed\n");
1617 ok(ret == ret2, "lengths of sort keys must be equal\n");
1618 ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
1620 /* test NORM_IGNORENONSPACE */
1621 lstrcpyW(buf, fooW);
1622 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
1623 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1624 ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
1625 lstrlenW(lower_case) + 1, ret);
1626 ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
1628 /* test NORM_IGNORESYMBOLS */
1629 lstrcpyW(buf, fooW);
1630 ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
1631 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
1632 ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
1633 lstrlenW(symbols_stripped) + 1, ret);
1634 ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
1636 /* test srclen = 0 */
1637 SetLastError(0xdeadbeef);
1638 ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
1639 ok(!ret, "LCMapStringW should fail with srclen = 0\n");
1640 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1641 "unexpected error code %d\n", GetLastError());
1644 static void test_LocaleNames(void)
1646 LCID lcid;
1647 INT ret;
1648 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
1650 if (!pLocaleNameToLCID)
1652 win_skip( "LocaleNameToLCID not available\n" );
1653 return;
1656 /* special cases */
1657 buffer[0] = 0;
1658 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
1659 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
1660 "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
1661 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1662 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1663 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1665 buffer[0] = 0;
1666 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
1667 todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
1668 "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
1669 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1670 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1671 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1673 buffer[0] = 0;
1674 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
1675 todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
1676 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
1677 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
1678 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
1681 /* this requires collation table patch to make it MS compatible */
1682 static const char * const strings_sorted[] =
1684 "'",
1685 "-",
1686 "!",
1687 "\"",
1688 ".",
1689 ":",
1690 "\\",
1691 "_",
1692 "`",
1693 "{",
1694 "}",
1695 "+",
1696 "0",
1697 "1",
1698 "2",
1699 "3",
1700 "4",
1701 "5",
1702 "6",
1703 "7",
1704 "8",
1705 "9",
1706 "a",
1707 "A",
1708 "b",
1709 "B",
1710 "c",
1714 static const char * const strings[] =
1716 "C",
1717 "\"",
1718 "9",
1719 "'",
1720 "}",
1721 "-",
1722 "7",
1723 "+",
1724 "`",
1725 "1",
1726 "a",
1727 "5",
1728 "\\",
1729 "8",
1730 "B",
1731 "3",
1732 "_",
1733 "6",
1734 "{",
1735 "2",
1736 "c",
1737 "4",
1738 "!",
1739 "0",
1740 "A",
1741 ":",
1742 "b",
1746 static int compare_string1(const void *e1, const void *e2)
1748 const char *s1 = *(const char *const *)e1;
1749 const char *s2 = *(const char *const *)e2;
1751 return lstrcmpA(s1, s2);
1754 static int compare_string2(const void *e1, const void *e2)
1756 const char *s1 = *(const char *const *)e1;
1757 const char *s2 = *(const char *const *)e2;
1759 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
1762 static int compare_string3(const void *e1, const void *e2)
1764 const char *s1 = *(const char *const *)e1;
1765 const char *s2 = *(const char *const *)e2;
1766 char key1[256], key2[256];
1768 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
1769 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
1770 return strcmp(key1, key2);
1773 static void test_sorting(void)
1775 char buf[256];
1776 char **str_buf = (char **)buf;
1777 int i;
1779 assert(sizeof(buf) >= sizeof(strings));
1781 /* 1. sort using lstrcmpA */
1782 memcpy(buf, strings, sizeof(strings));
1783 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
1784 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1786 ok(!strcmp(strings_sorted[i], str_buf[i]),
1787 "qsort using lstrcmpA failed for element %d\n", i);
1789 /* 2. sort using CompareStringA */
1790 memcpy(buf, strings, sizeof(strings));
1791 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
1792 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1794 ok(!strcmp(strings_sorted[i], str_buf[i]),
1795 "qsort using CompareStringA failed for element %d\n", i);
1797 /* 3. sort using sort keys */
1798 memcpy(buf, strings, sizeof(strings));
1799 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
1800 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
1802 ok(!strcmp(strings_sorted[i], str_buf[i]),
1803 "qsort using sort keys failed for element %d\n", i);
1807 static void test_FoldStringA(void)
1809 int ret, i, j;
1810 BOOL is_special;
1811 char src[256], dst[256];
1812 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
1813 static const char digits_dst[] = { '1','2','3','\0' };
1814 static const char composite_src[] =
1816 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
1817 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
1818 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
1819 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
1820 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
1821 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
1822 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
1823 0xfb,0xfc,0xfd,0xff,'\0'
1825 static const char composite_dst[] =
1827 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1828 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1829 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1830 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1831 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1832 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1833 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
1834 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
1835 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
1836 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
1837 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
1838 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
1839 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
1840 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
1841 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1843 static const char composite_dst_alt[] =
1845 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
1846 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
1847 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
1848 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
1849 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
1850 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
1851 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
1852 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
1853 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
1854 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
1855 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
1856 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
1857 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
1858 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
1859 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
1861 static const char ligatures_src[] =
1863 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
1865 static const char ligatures_dst[] =
1867 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
1869 static const struct special
1871 char src;
1872 char dst[4];
1873 } foldczone_special[] =
1875 /* src dst */
1876 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
1877 { 0x98, { 0x20, 0x7e, 0x00 } },
1878 { 0x99, { 0x54, 0x4d, 0x00 } },
1879 { 0xa0, { 0x20, 0x00 } },
1880 { 0xa8, { 0x20, 0xa8, 0x00 } },
1881 { 0xaa, { 0x61, 0x00 } },
1882 { 0xaf, { 0x20, 0xaf, 0x00 } },
1883 { 0xb2, { 0x32, 0x00 } },
1884 { 0xb3, { 0x33, 0x00 } },
1885 { 0xb4, { 0x20, 0xb4, 0x00 } },
1886 { 0xb8, { 0x20, 0xb8, 0x00 } },
1887 { 0xb9, { 0x31, 0x00 } },
1888 { 0xba, { 0x6f, 0x00 } },
1889 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
1890 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
1891 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
1892 { 0x00 }
1895 if (!pFoldStringA)
1896 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
1898 /* these tests are locale specific */
1899 if (GetACP() != 1252)
1901 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
1902 return;
1905 /* MAP_FOLDDIGITS */
1906 SetLastError(0);
1907 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
1908 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1910 win_skip("FoldStringA is not implemented\n");
1911 return;
1913 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
1914 ok(strcmp(dst, digits_dst) == 0,
1915 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
1916 for (i = 1; i < 256; i++)
1918 if (!strchr(digits_src, i))
1920 src[0] = i;
1921 src[1] = '\0';
1922 SetLastError(0);
1923 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
1924 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1925 ok(dst[0] == src[0],
1926 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
1930 /* MAP_EXPAND_LIGATURES */
1931 SetLastError(0);
1932 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
1933 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
1934 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
1935 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
1936 ok(strcmp(dst, ligatures_dst) == 0,
1937 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
1938 for (i = 1; i < 256; i++)
1940 if (!strchr(ligatures_src, i))
1942 src[0] = i;
1943 src[1] = '\0';
1944 SetLastError(0);
1945 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
1946 if (ret == 3)
1948 /* Vista */
1949 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
1950 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
1951 "Got %s for %d\n", dst, i);
1953 else
1955 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1956 ok(dst[0] == src[0],
1957 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
1963 /* MAP_COMPOSITE */
1964 SetLastError(0);
1965 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
1966 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1967 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
1968 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
1969 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
1971 for (i = 1; i < 256; i++)
1973 if (!strchr(composite_src, i))
1975 src[0] = i;
1976 src[1] = '\0';
1977 SetLastError(0);
1978 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
1979 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
1980 ok(dst[0] == src[0],
1981 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
1982 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
1986 /* MAP_FOLDCZONE */
1987 for (i = 1; i < 256; i++)
1989 src[0] = i;
1990 src[1] = '\0';
1991 SetLastError(0);
1992 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
1993 is_special = FALSE;
1994 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
1996 if (foldczone_special[j].src == src[0])
1998 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
1999 "Expected ret == 2 or %d, got %d, error %d\n",
2000 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
2001 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
2002 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
2003 (unsigned char)src[0]);
2004 is_special = TRUE;
2007 if (! is_special)
2009 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2010 ok(src[0] == dst[0],
2011 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
2012 (unsigned char)src[0], (unsigned char)dst[0]);
2016 /* MAP_PRECOMPOSED */
2017 for (i = 1; i < 256; i++)
2019 src[0] = i;
2020 src[1] = '\0';
2021 SetLastError(0);
2022 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
2023 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2024 ok(src[0] == dst[0],
2025 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
2026 (unsigned char)src[0], (unsigned char)dst[0]);
2030 static void test_FoldStringW(void)
2032 int ret;
2033 unsigned int i, j;
2034 WCHAR src[256], dst[256], ch, prev_ch = 1;
2035 static const DWORD badFlags[] =
2038 MAP_PRECOMPOSED|MAP_COMPOSITE,
2039 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
2040 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
2042 /* Ranges of digits 0-9 : Must be sorted! */
2043 static const WCHAR digitRanges[] =
2045 0x0030, /* '0'-'9' */
2046 0x0660, /* Eastern Arabic */
2047 0x06F0, /* Arabic - Hindu */
2048 0x0966, /* Devengari */
2049 0x09E6, /* Bengalii */
2050 0x0A66, /* Gurmukhi */
2051 0x0AE6, /* Gujarati */
2052 0x0B66, /* Oriya */
2053 0x0BE6, /* Tamil - No 0 */
2054 0x0C66, /* Telugu */
2055 0x0CE6, /* Kannada */
2056 0x0D66, /* Maylayalam */
2057 0x0E50, /* Thai */
2058 0x0ED0, /* Laos */
2059 0x0F29, /* Tibet - 0 is out of sequence */
2060 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
2061 0x2080, /* Subscript */
2062 0x245F, /* Circled - 0 is out of sequence */
2063 0x2473, /* Bracketed */
2064 0x2487, /* Full stop */
2065 0x2775, /* Inverted circled - No 0 */
2066 0x277F, /* Patterned circled - No 0 */
2067 0x2789, /* Inverted Patterned circled - No 0 */
2068 0x3020, /* Hangzhou */
2069 0xff10, /* Pliene chasse (?) */
2070 0xffff /* Terminator */
2072 /* Digits which are represented, but out of sequence */
2073 static const WCHAR outOfSequenceDigits[] =
2075 0xB9, /* Superscript 1 */
2076 0xB2, /* Superscript 2 */
2077 0xB3, /* Superscript 3 */
2078 0x0F33, /* Tibetan half zero */
2079 0x24EA, /* Circled 0 */
2080 0x3007, /* Ideographic number zero */
2081 '\0' /* Terminator */
2083 /* Digits in digitRanges for which no representation is available */
2084 static const WCHAR noDigitAvailable[] =
2086 0x0BE6, /* No Tamil 0 */
2087 0x0F29, /* No Tibetan half zero (out of sequence) */
2088 0x2473, /* No Bracketed 0 */
2089 0x2487, /* No 0 Full stop */
2090 0x2775, /* No inverted circled 0 */
2091 0x277F, /* No patterned circled */
2092 0x2789, /* No inverted Patterned circled */
2093 0x3020, /* No Hangzhou 0 */
2094 '\0' /* Terminator */
2096 static const WCHAR foldczone_src[] =
2098 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
2099 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
2101 static const WCHAR foldczone_dst[] =
2103 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
2105 static const WCHAR foldczone_todo_src[] =
2107 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
2109 static const WCHAR foldczone_todo_dst[] =
2111 0x3cb,0x1f0,' ','a',0
2113 static const WCHAR foldczone_todo_broken_dst[] =
2115 0x3cb,0x1f0,0xa0,0xaa,0
2117 static const WCHAR ligatures_src[] =
2119 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
2120 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
2121 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
2122 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
2123 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
2124 0xfb04, 0xfb05, 0xfb06, '\0'
2126 static const WCHAR ligatures_dst[] =
2128 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
2129 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
2130 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
2131 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
2132 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
2133 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
2136 if (!pFoldStringW)
2138 win_skip("FoldStringW is not available\n");
2139 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2142 /* Invalid flag combinations */
2143 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
2145 src[0] = dst[0] = '\0';
2146 SetLastError(0);
2147 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
2148 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
2150 win_skip("FoldStringW is not implemented\n");
2151 return;
2153 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
2154 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2157 /* src & dst cannot be the same */
2158 SetLastError(0);
2159 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
2160 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2161 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2163 /* src can't be NULL */
2164 SetLastError(0);
2165 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
2166 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2167 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2169 /* srclen can't be 0 */
2170 SetLastError(0);
2171 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
2172 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2173 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2175 /* dstlen can't be < 0 */
2176 SetLastError(0);
2177 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
2178 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2179 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2181 /* Ret includes terminating NUL which is appended if srclen = -1 */
2182 SetLastError(0);
2183 src[0] = 'A';
2184 src[1] = '\0';
2185 dst[0] = '\0';
2186 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
2187 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2188 ok(dst[0] == 'A' && dst[1] == '\0',
2189 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
2190 'A', '\0', ret, dst[0], dst[1], GetLastError());
2192 /* If size is given, result is not NUL terminated */
2193 SetLastError(0);
2194 src[0] = 'A';
2195 src[1] = 'A';
2196 dst[0] = 'X';
2197 dst[1] = 'X';
2198 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
2199 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
2200 ok(dst[0] == 'A' && dst[1] == 'X',
2201 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
2202 'A','X', ret, dst[0], dst[1], GetLastError());
2204 /* MAP_FOLDDIGITS */
2205 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
2207 /* Check everything before this range */
2208 for (ch = prev_ch; ch < digitRanges[j]; ch++)
2210 SetLastError(0);
2211 src[0] = ch;
2212 src[1] = dst[0] = '\0';
2213 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2214 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2216 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
2217 /* Wine (correctly) maps all Unicode 4.0+ digits */
2218 isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
2219 (ch >= 0x1369 && ch <= 0x1371),
2220 "MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
2223 if (digitRanges[j] == 0xffff)
2224 break; /* Finished the whole code point space */
2226 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
2228 WCHAR c;
2230 /* Map out of sequence characters */
2231 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
2232 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
2233 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
2234 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
2235 else c = ch;
2236 SetLastError(0);
2237 src[0] = c;
2238 src[1] = dst[0] = '\0';
2239 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
2240 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2242 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
2243 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
2244 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
2245 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
2246 strchrW(noDigitAvailable, c),
2247 "MAP_FOLDDIGITS: ch %d Expected %d got %d\n",
2248 ch, '0' + digitRanges[j] - ch, dst[0]);
2250 prev_ch = ch;
2253 /* MAP_FOLDCZONE */
2254 SetLastError(0);
2255 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
2256 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
2257 "Got %d, error %d\n", ret, GetLastError());
2258 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
2259 "MAP_FOLDCZONE: Expanded incorrectly\n");
2261 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
2262 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
2263 "Got %d, error %d\n", ret, GetLastError());
2264 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
2265 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
2266 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
2268 /* MAP_EXPAND_LIGATURES */
2269 SetLastError(0);
2270 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
2271 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
2272 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
2273 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
2274 "Got %d, error %d\n", ret, GetLastError());
2275 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
2276 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
2279 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
2284 #define LCID_OK(l) \
2285 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
2286 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
2287 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
2288 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
2289 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
2291 static void test_ConvertDefaultLocale(void)
2293 LCID lcid;
2295 /* Doesn't change lcid, even if non default sublang/sort used */
2296 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
2297 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
2298 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
2299 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
2301 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
2302 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
2303 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
2304 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
2305 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
2307 /* Invariant language is not treated specially */
2308 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
2310 /* User/system default languages alone are not mapped */
2311 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
2312 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
2314 /* Default lcids */
2315 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
2316 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
2317 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
2320 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
2321 DWORD dwFlags, LONG_PTR lParam)
2323 trace("%08x, %s, %s, %08x, %08lx\n",
2324 lgrpid, lpszNum, lpszName, dwFlags, lParam);
2326 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
2327 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
2329 /* If lParam is one, we are calling with flags defaulted from 0 */
2330 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
2331 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
2333 return TRUE;
2336 static void test_EnumSystemLanguageGroupsA(void)
2338 BOOL ret;
2340 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
2342 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
2343 return;
2346 /* No enumeration proc */
2347 SetLastError(0);
2348 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
2349 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2351 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
2352 return;
2354 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2355 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2357 /* Invalid flags */
2358 SetLastError(0);
2359 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
2360 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2362 /* No flags - defaults to LGRPID_INSTALLED */
2363 SetLastError(0xdeadbeef);
2364 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
2365 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
2367 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
2368 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
2371 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
2373 trace( "%s %x\n", wine_dbgstr_w(name), flags );
2374 return TRUE;
2377 static void test_EnumSystemLocalesEx(void)
2379 BOOL ret;
2381 if (!pEnumSystemLocalesEx)
2383 win_skip( "EnumSystemLocalesEx not available\n" );
2384 return;
2386 SetLastError( 0xdeadbeef );
2387 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
2388 ok( !ret, "should have failed\n" );
2389 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2390 SetLastError( 0xdeadbeef );
2391 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
2392 ok( ret, "failed err %u\n", GetLastError() );
2395 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
2396 LONG_PTR lParam)
2398 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
2400 /* invalid locale enumerated on some platforms */
2401 if (lcid == 0)
2402 return TRUE;
2404 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
2405 "Enumerated grp %d not valid\n", lgrpid);
2406 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
2407 "Enumerated grp locale %d not valid\n", lcid);
2408 return TRUE;
2411 static void test_EnumLanguageGroupLocalesA(void)
2413 BOOL ret;
2415 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
2417 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
2418 return;
2421 /* No enumeration proc */
2422 SetLastError(0);
2423 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
2424 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2426 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
2427 return;
2429 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2430 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2432 /* lgrpid too small */
2433 SetLastError(0);
2434 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
2435 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2436 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2438 /* lgrpid too big */
2439 SetLastError(0);
2440 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
2441 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2442 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2444 /* dwFlags is reserved */
2445 SetLastError(0);
2446 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
2447 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
2448 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2450 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
2453 static void test_SetLocaleInfoA(void)
2455 BOOL bRet;
2456 LCID lcid = GetUserDefaultLCID();
2458 /* Null data */
2459 SetLastError(0);
2460 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
2461 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
2462 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2464 /* IDATE */
2465 SetLastError(0);
2466 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
2467 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2468 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2470 /* ILDATE */
2471 SetLastError(0);
2472 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
2473 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
2474 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2477 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
2479 trace("%s %08lx\n", value, lParam);
2480 return(TRUE);
2483 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
2485 ok(!enumCount, "callback called again unexpected\n");
2486 enumCount++;
2487 return(FALSE);
2490 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
2492 ok(0,"callback called unexpected\n");
2493 return(FALSE);
2496 static void test_EnumUILanguageA(void)
2498 BOOL ret;
2499 if (!pEnumUILanguagesA) {
2500 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
2501 return;
2504 SetLastError(ERROR_SUCCESS);
2505 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
2506 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2508 win_skip("EnumUILanguagesA is not implemented\n");
2509 return;
2511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2513 enumCount = 0;
2514 SetLastError(ERROR_SUCCESS);
2515 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
2516 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
2518 SetLastError(ERROR_SUCCESS);
2519 ret = pEnumUILanguagesA(NULL, 0, 0);
2520 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2521 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2522 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2524 SetLastError(ERROR_SUCCESS);
2525 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
2526 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2527 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
2529 SetLastError(ERROR_SUCCESS);
2530 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
2531 ok(!ret, "Expected return value FALSE, got %u\n", ret);
2532 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2533 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2536 static char date_fmt_buf[1024];
2538 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
2540 lstrcatA(date_fmt_buf, fmt);
2541 lstrcatA(date_fmt_buf, "\n");
2542 return TRUE;
2545 static void test_EnumDateFormatsA(void)
2547 char *p, buf[256];
2548 BOOL ret;
2549 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2551 trace("EnumDateFormatsA 0\n");
2552 date_fmt_buf[0] = 0;
2553 SetLastError(0xdeadbeef);
2554 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
2555 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2557 win_skip("0 for dwFlags is not supported\n");
2559 else
2561 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
2562 trace("%s\n", date_fmt_buf);
2563 /* test the 1st enumerated format */
2564 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2565 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2566 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2567 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2570 trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
2571 date_fmt_buf[0] = 0;
2572 SetLastError(0xdeadbeef);
2573 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2574 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2576 win_skip("LOCALE_USE_CP_ACP is not supported\n");
2578 else
2580 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2581 trace("%s\n", date_fmt_buf);
2582 /* test the 1st enumerated format */
2583 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2584 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2585 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2586 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2589 trace("EnumDateFormatsA DATE_SHORTDATE\n");
2590 date_fmt_buf[0] = 0;
2591 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
2592 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
2593 trace("%s\n", date_fmt_buf);
2594 /* test the 1st enumerated format */
2595 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2596 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
2597 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
2598 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2600 trace("EnumDateFormatsA DATE_LONGDATE\n");
2601 date_fmt_buf[0] = 0;
2602 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
2603 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
2604 trace("%s\n", date_fmt_buf);
2605 /* test the 1st enumerated format */
2606 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2607 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
2608 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
2609 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2611 trace("EnumDateFormatsA DATE_YEARMONTH\n");
2612 date_fmt_buf[0] = 0;
2613 SetLastError(0xdeadbeef);
2614 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
2615 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
2617 skip("DATE_YEARMONTH is only present on W2K and later\n");
2618 return;
2620 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
2621 trace("%s\n", date_fmt_buf);
2622 /* test the 1st enumerated format */
2623 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2624 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
2625 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
2626 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
2627 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2630 static void test_EnumTimeFormatsA(void)
2632 char *p, buf[256];
2633 BOOL ret;
2634 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
2636 trace("EnumTimeFormatsA 0\n");
2637 date_fmt_buf[0] = 0;
2638 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
2639 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
2640 trace("%s\n", date_fmt_buf);
2641 /* test the 1st enumerated format */
2642 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2643 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2644 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2645 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2647 trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
2648 date_fmt_buf[0] = 0;
2649 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
2650 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
2651 trace("%s\n", date_fmt_buf);
2652 /* test the 1st enumerated format */
2653 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
2654 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
2655 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
2656 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
2659 static void test_GetCPInfo(void)
2661 BOOL ret;
2662 CPINFO cpinfo;
2664 SetLastError(0xdeadbeef);
2665 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
2666 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
2667 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2668 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
2670 SetLastError(0xdeadbeef);
2671 ret = GetCPInfo(CP_UTF7, &cpinfo);
2672 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2674 skip("Codepage CP_UTF7 is not installed/available\n");
2676 else
2678 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
2679 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2680 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2681 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2682 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2683 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
2686 SetLastError(0xdeadbeef);
2687 ret = GetCPInfo(CP_UTF8, &cpinfo);
2688 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
2690 skip("Codepage CP_UTF8 is not installed/available\n");
2692 else
2694 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
2695 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
2696 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
2697 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
2698 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
2699 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
2700 "expected 4, got %u\n", cpinfo.MaxCharSize);
2705 * The CT_TYPE1 has varied over windows version.
2706 * The current target for correct behavior is windows 7.
2707 * There was a big shift between windows 2000 (first introduced) and windows Xp
2708 * Most of the old values below are from windows 2000.
2709 * A smaller subset of changes happened between windows Xp and Window vista/7
2711 static void test_GetStringTypeW(void)
2713 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
2714 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
2715 C1_SPACE | C1_BLANK | C1_DEFINED,
2716 C1_SPACE | C1_BLANK | C1_DEFINED,
2717 C1_SPACE | C1_BLANK | C1_DEFINED,
2718 C1_CNTRL | C1_BLANK | C1_DEFINED};
2719 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
2720 C1_SPACE | C1_BLANK,
2721 C1_SPACE | C1_BLANK,
2722 C1_SPACE | C1_BLANK,
2723 C1_SPACE | C1_BLANK};
2725 static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
2727 /* Lu, Ll, Lt */
2728 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
2729 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
2730 C1_LOWER | C1_ALPHA,
2731 C1_UPPER | C1_LOWER | C1_ALPHA,
2732 C1_ALPHA};
2734 /* Sk, Sk, Mn, So, Me */
2735 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
2736 /* Sc, Sm, No,*/
2737 0xffe0, 0xffe9, 0x2153};
2739 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
2740 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
2741 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
2742 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
2743 C1_ALPHA | C1_DEFINED,
2744 C1_CNTRL | C1_DEFINED,
2745 C1_PUNCT | C1_DEFINED,
2746 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2747 C1_ALPHA | C1_LOWER | C1_DEFINED,
2748 C1_ALPHA | C1_DEFINED };
2749 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
2750 C1_ALPHA | C1_DEFINED,
2751 C1_CNTRL | C1_DEFINED,
2752 C1_PUNCT | C1_CNTRL | C1_DEFINED,
2753 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
2754 C1_ALPHA | C1_DEFINED,
2755 C1_DEFINED
2757 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
2758 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
2760 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
2761 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
2762 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
2763 static const WCHAR lower_special[] = {0x2071, 0x207f};
2764 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
2765 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
2766 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
2767 0xfff9, 0xfffa, 0xfffb};
2768 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
2770 WORD types[20];
2771 int i;
2773 memset(types,0,sizeof(types));
2774 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
2775 for (i = 0; i < 5; i++)
2776 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]);
2778 memset(types,0,sizeof(types));
2779 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
2780 for (i = 0; i < 3; i++)
2781 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]));
2782 memset(types,0,sizeof(types));
2783 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
2784 for (i = 0; i < 5; i++)
2785 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
2787 memset(types,0,sizeof(types));
2788 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
2789 for (i = 0; i < 8; i++)
2790 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);
2792 memset(types,0,sizeof(types));
2793 GetStringTypeW(CT_CTYPE1, changed, 7, types);
2794 for (i = 0; i < 7; i++)
2795 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]);
2797 memset(types,0,sizeof(types));
2798 GetStringTypeW(CT_CTYPE1, punct, 7, types);
2799 for (i = 0; i < 7; i++)
2800 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));
2803 memset(types,0,sizeof(types));
2804 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
2805 for (i = 0; i < 12; i++)
2806 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);
2808 memset(types,0,sizeof(types));
2809 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
2810 for (i = 0; i < 3; i++)
2811 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);
2813 memset(types,0,sizeof(types));
2814 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
2815 for (i = 0; i < 2; i++)
2816 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);
2818 memset(types,0,sizeof(types));
2819 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
2820 for (i = 0; i < 20; i++)
2821 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);
2823 memset(types,0,sizeof(types));
2824 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
2825 for (i = 0; i < 3; i++)
2826 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 );
2829 START_TEST(locale)
2831 InitFunctionPointers();
2833 test_EnumTimeFormatsA();
2834 test_EnumDateFormatsA();
2835 test_GetLocaleInfoA();
2836 test_GetLocaleInfoW();
2837 test_GetTimeFormatA();
2838 test_GetDateFormatA();
2839 test_GetDateFormatW();
2840 test_GetCurrencyFormatA(); /* Also tests the W version */
2841 test_GetNumberFormatA(); /* Also tests the W version */
2842 test_CompareStringA();
2843 test_LCMapStringA();
2844 test_LCMapStringW();
2845 test_LocaleNames();
2846 test_FoldStringA();
2847 test_FoldStringW();
2848 test_ConvertDefaultLocale();
2849 test_EnumSystemLanguageGroupsA();
2850 test_EnumSystemLocalesEx();
2851 test_EnumLanguageGroupLocalesA();
2852 test_SetLocaleInfoA();
2853 test_EnumUILanguageA();
2854 test_GetCPInfo();
2855 test_GetStringTypeW();
2856 /* this requires collation table patch to make it MS compatible */
2857 if (0) test_sorting();