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