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