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