kernel32/tests: Fix check for invalid type value.
[wine.git] / dlls / kernel32 / tests / locale.c
blob5d5cc178c3d11263c4eb5b940391d47be1c8d392
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 title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
42 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
43 static const WCHAR localeW[] = {'e','n','-','U','S',0};
44 static const WCHAR fooW[] = {'f','o','o',0};
45 static const WCHAR emptyW[] = {0};
46 static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
48 static inline unsigned int strlenW( const WCHAR *str )
50 const WCHAR *s = str;
51 while (*s) s++;
52 return s - str;
55 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
57 if (n <= 0) return 0;
58 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
59 return *str1 - *str2;
62 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
64 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
65 return NULL;
68 static inline BOOL isdigitW( WCHAR wc )
70 WORD type;
71 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
72 return type & C1_DIGIT;
75 /* Some functions are only in later versions of kernel32.dll */
76 static WORD enumCount;
78 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
79 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
80 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
83 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
84 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
85 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
86 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
87 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
88 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
90 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
93 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
94 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
95 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
96 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
97 LPNLSVERSIONINFO, LPVOID, LPARAM);
98 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
99 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
100 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
101 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
103 static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
104 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
105 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
106 static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
108 static void InitFunctionPointers(void)
110 HMODULE mod = GetModuleHandleA("kernel32");
112 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
113 X(GetTimeFormatEx);
114 X(GetDateFormatEx);
115 X(EnumSystemLanguageGroupsA);
116 X(EnumLanguageGroupLocalesA);
117 X(LocaleNameToLCID);
118 X(LCIDToLocaleName);
119 X(LCMapStringEx);
120 X(FoldStringA);
121 X(FoldStringW);
122 X(IsValidLanguageGroup);
123 X(EnumUILanguagesA);
124 X(EnumSystemLocalesEx);
125 X(IdnToNameprepUnicode);
126 X(IdnToAscii);
127 X(IdnToUnicode);
128 X(GetLocaleInfoEx);
129 X(IsValidLocaleName);
130 X(CompareStringOrdinal);
131 X(CompareStringEx);
132 X(GetGeoInfoA);
133 X(GetGeoInfoW);
134 X(EnumSystemGeoID);
135 X(GetSystemPreferredUILanguages);
136 X(GetThreadPreferredUILanguages);
137 X(GetUserPreferredUILanguages);
138 X(GetNumberFormatEx);
139 X(FindNLSStringEx);
141 mod = GetModuleHandleA("ntdll");
142 X(RtlUpcaseUnicodeChar);
143 #undef X
146 #define eq(received, expected, label, type) \
147 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
148 (label), (received), (expected))
150 #define BUFFER_SIZE 128
151 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
153 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
154 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
155 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
156 "Expected '%s', got '%s'\n", Expected, buffer)
158 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
159 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
160 SetLastError(0xdeadbeef); buffer[0] = '\0'
161 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
162 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
164 #define NUO LOCALE_NOUSEROVERRIDE
166 static void test_GetLocaleInfoA(void)
168 int ret;
169 int len;
170 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
171 char buffer[BUFFER_SIZE];
172 char expected[BUFFER_SIZE];
173 DWORD val;
175 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
177 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
178 ok(ret, "got %d\n", ret);
179 ok(val == lcid, "got 0x%08x\n", val);
181 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
182 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
183 assumes SUBLANG_NEUTRAL for zh */
184 memset(expected, 0, COUNTOF(expected));
185 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
186 SetLastError(0xdeadbeef);
187 memset(buffer, 0, COUNTOF(buffer));
188 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
189 ok((ret == len) && !lstrcmpA(buffer, expected),
190 "got %d with '%s' (expected %d with '%s')\n",
191 ret, buffer, len, expected);
193 memset(expected, 0, COUNTOF(expected));
194 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
195 if (len) {
196 SetLastError(0xdeadbeef);
197 memset(buffer, 0, COUNTOF(buffer));
198 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
199 ok((ret == len) && !lstrcmpA(buffer, expected),
200 "got %d with '%s' (expected %d with '%s')\n",
201 ret, buffer, len, expected);
203 else
204 win_skip("LANG_ARABIC not installed\n");
206 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
207 memset(expected, 0, COUNTOF(expected));
208 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
209 SetLastError(0xdeadbeef);
210 memset(buffer, 0, COUNTOF(buffer));
211 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
212 ok((ret == len) && !lstrcmpA(buffer, expected),
213 "got %d with '%s' (expected %d with '%s')\n",
214 ret, buffer, len, expected);
217 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
218 * partially fill the buffer even if it is too short. See bug 637.
220 SetLastError(0xdeadbeef);
221 memset(buffer, 0, COUNTOF(buffer));
222 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
223 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
225 SetLastError(0xdeadbeef);
226 memset(buffer, 0, COUNTOF(buffer));
227 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
228 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
229 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
230 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
232 SetLastError(0xdeadbeef);
233 memset(buffer, 0, COUNTOF(buffer));
234 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
235 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
236 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
239 struct neutralsublang_name2_t {
240 WCHAR name[3];
241 WCHAR sname[15];
242 LCID lcid;
243 LCID lcid_broken;
244 WCHAR sname_broken[15];
245 int todo;
248 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
249 { {'a','r',0}, {'a','r','-','S','A',0},
250 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
251 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
252 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
253 { {'d','e',0}, {'d','e','-','D','E',0},
254 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
255 { {'e','n',0}, {'e','n','-','U','S',0},
256 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
257 { {'e','s',0}, {'e','s','-','E','S',0},
258 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
259 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
260 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
261 { {'g','a',0}, {'g','a','-','I','E',0},
262 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
263 { {'i','t',0}, {'i','t','-','I','T',0},
264 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
265 { {'m','s',0}, {'m','s','-','M','Y',0},
266 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
267 { {'n','l',0}, {'n','l','-','N','L',0},
268 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
269 { {'p','t',0}, {'p','t','-','B','R',0},
270 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
271 { {'s','r',0}, {'h','r','-','H','R',0},
272 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
273 { {'s','v',0}, {'s','v','-','S','E',0},
274 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
275 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
276 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
277 { {'z','h',0}, {'z','h','-','C','N',0},
278 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
279 { {0} }
282 static void test_GetLocaleInfoW(void)
284 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
285 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
286 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
287 WCHAR bufferW[80], buffer2W[80];
288 CHAR bufferA[80];
289 DWORD val;
290 DWORD ret;
291 INT i;
293 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
294 if (!ret) {
295 win_skip("GetLocaleInfoW() isn't implemented\n");
296 return;
299 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
300 ok(ret, "got %d\n", ret);
301 ok(val == lcid_en, "got 0x%08x\n", val);
303 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
304 if (ret)
306 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
307 'S','t','a','t','e','s',')',0};
308 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
309 static const WCHAR enW[] = {'e','n','-','U','S',0};
310 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
312 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
314 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
315 ok(ret, "got %d\n", ret);
316 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
317 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
319 skip("Non-English locale\n");
321 else
322 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
324 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
325 ok(ret, "got %d\n", ret);
326 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
327 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
329 skip("Non-English locale\n");
331 else
332 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
334 while (*ptr->name)
336 LANGID langid;
337 LCID lcid;
339 /* make neutral lcid */
340 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
341 lcid = MAKELCID(langid, SORT_DEFAULT);
343 val = 0;
344 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
345 todo_wine_if (ptr->todo & 0x1)
346 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
347 wine_dbgstr_w(ptr->name), val, ptr->lcid);
349 /* now check LOCALE_SNAME */
350 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
351 todo_wine_if (ptr->todo & 0x2)
352 ok(!lstrcmpW(bufferW, ptr->sname) ||
353 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
354 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
355 ptr++;
358 else
359 win_skip("English neutral locale not supported\n");
361 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
362 if (!ret) {
363 win_skip("LANG_RUSSIAN locale data unavailable\n");
364 return;
366 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
367 bufferW, COUNTOF(bufferW));
368 if (!ret) {
369 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
370 return;
373 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
374 bufferA[0] = 'a';
375 SetLastError(0xdeadbeef);
376 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
377 bufferA, COUNTOF(bufferA));
378 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
379 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
380 ok(GetLastError() == ERROR_INVALID_FLAGS,
381 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
383 bufferW[0] = 'a';
384 SetLastError(0xdeadbeef);
385 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
386 bufferW, COUNTOF(bufferW));
387 ok(ret == 0,
388 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
389 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
390 ok(GetLastError() == ERROR_INVALID_FLAGS,
391 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
393 /* yes, test empty 13 month entry too */
394 for (i = 0; i < 12; i++) {
395 bufferW[0] = 0;
396 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
397 bufferW, COUNTOF(bufferW));
398 ok(ret, "Expected non zero result\n");
399 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
400 ret, lstrlenW(bufferW));
401 buffer2W[0] = 0;
402 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
403 buffer2W, COUNTOF(buffer2W));
404 ok(ret, "Expected non zero result\n");
405 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
406 ret, lstrlenW(buffer2W));
408 ok(lstrcmpW(bufferW, buffer2W) != 0,
409 "Expected genitive name to differ, got the same for month %d\n", i+1);
411 /* for locale without genitive names nominative returned in both cases */
412 bufferW[0] = 0;
413 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
414 bufferW, COUNTOF(bufferW));
415 ok(ret, "Expected non zero result\n");
416 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
417 ret, lstrlenW(bufferW));
418 buffer2W[0] = 0;
419 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
420 buffer2W, COUNTOF(buffer2W));
421 ok(ret, "Expected non zero result\n");
422 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
423 ret, lstrlenW(buffer2W));
425 ok(lstrcmpW(bufferW, buffer2W) == 0,
426 "Expected same names, got different for month %d\n", i+1);
430 static void test_GetTimeFormatA(void)
432 int ret;
433 SYSTEMTIME curtime;
434 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
435 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
437 memset(&curtime, 2, sizeof(SYSTEMTIME));
438 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
439 SetLastError(0xdeadbeef);
440 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
441 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
442 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
444 curtime.wHour = 8;
445 curtime.wMinute = 56;
446 curtime.wSecond = 13;
447 curtime.wMilliseconds = 22;
448 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
449 SetLastError(0xdeadbeef);
450 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
451 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
452 EXPECT_LENA; EXPECT_EQA;
454 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
455 SetLastError(0xdeadbeef);
456 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
457 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
458 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
460 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
461 SetLastError(0xdeadbeef);
462 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
463 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
464 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
466 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
467 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
468 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
469 EXPECT_LENA;
471 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
472 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
473 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
474 EXPECT_LENA; EXPECT_EQA;
476 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
477 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
478 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
479 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
480 "Expected '', got '%s'\n", buffer );
482 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
483 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
484 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
485 EXPECT_LENA; EXPECT_EQA;
487 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
488 strcpy(Expected, "8:56 AM");
489 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
490 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
491 EXPECT_LENA; EXPECT_EQA;
493 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
494 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
495 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
496 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
497 "Expected '8.@:56AM', got '%s'\n", buffer );
499 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
500 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
501 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
502 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
503 "Expected '', got '%s'\n", buffer );
505 STRINGSA("t/tt", "A/AM"); /* AM time marker */
506 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
507 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
508 EXPECT_LENA; EXPECT_EQA;
510 curtime.wHour = 13;
511 STRINGSA("t/tt", "P/PM"); /* PM time marker */
512 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
513 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
514 EXPECT_LENA; EXPECT_EQA;
516 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
517 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
518 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
519 EXPECT_LENA; EXPECT_EQA;
521 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
522 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
523 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
524 EXPECT_LENA; EXPECT_EQA;
526 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
527 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
528 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
529 EXPECT_LENA; EXPECT_EQA;
531 curtime.wHour = 14; /* change this to 14 or 2pm */
532 curtime.wMinute = 5;
533 curtime.wSecond = 3;
534 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 */
535 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
536 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
537 EXPECT_LENA; EXPECT_EQA;
539 curtime.wHour = 0;
540 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
541 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
543 EXPECT_LENA; EXPECT_EQA;
545 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
546 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
547 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
548 EXPECT_LENA; EXPECT_EQA;
550 /* try to convert formatting strings with more than two letters
551 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
552 * NOTE: We expect any letter for which there is an upper case value
553 * we should see a replacement. For letters that DO NOT have
554 * upper case values we should see NO REPLACEMENT.
556 curtime.wHour = 8;
557 curtime.wMinute = 56;
558 curtime.wSecond = 13;
559 curtime.wMilliseconds = 22;
560 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
561 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
562 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
563 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
564 EXPECT_LENA; EXPECT_EQA;
566 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
567 strcpy(buffer, "text");
568 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
569 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
570 EXPECT_EQA;
572 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
573 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
574 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
575 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
576 EXPECT_LENA; EXPECT_EQA;
578 STRINGSA("'''", "'"); /* invalid quoted string */
579 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
580 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
581 EXPECT_LENA; EXPECT_EQA;
583 /* test that msdn suggested single quotation usage works as expected */
584 STRINGSA("''''", "'"); /* single quote mark */
585 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
586 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
587 EXPECT_LENA; EXPECT_EQA;
589 STRINGSA("''HHHHHH", "08"); /* Normal use */
590 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
591 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
592 EXPECT_LENA; EXPECT_EQA;
594 /* and test for normal use of the single quotation mark */
595 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
596 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
597 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
598 EXPECT_LENA; EXPECT_EQA;
600 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
601 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
602 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
603 EXPECT_LENA; EXPECT_EQA;
605 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
606 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
607 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
608 EXPECT_LENA; EXPECT_EQA;
610 curtime.wHour = 25;
611 STRINGSA("'123'tt", ""); /* Invalid time */
612 SetLastError(0xdeadbeef);
613 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
614 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
615 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
617 curtime.wHour = 12;
618 curtime.wMonth = 60; /* Invalid */
619 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
620 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
621 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
622 EXPECT_LENA; EXPECT_EQA;
625 static void test_GetTimeFormatEx(void)
627 int ret;
628 SYSTEMTIME curtime;
629 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
631 if (!pGetTimeFormatEx)
633 win_skip("GetTimeFormatEx not supported\n");
634 return;
637 memset(&curtime, 2, sizeof(SYSTEMTIME));
638 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
639 SetLastError(0xdeadbeef);
640 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
641 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
642 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
644 curtime.wHour = 8;
645 curtime.wMinute = 56;
646 curtime.wSecond = 13;
647 curtime.wMilliseconds = 22;
648 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
649 SetLastError(0xdeadbeef);
650 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
651 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
652 EXPECT_LENW; EXPECT_EQW;
654 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
655 SetLastError(0xdeadbeef);
656 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
657 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
658 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
660 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
661 SetLastError(0xdeadbeef);
662 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
663 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
664 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
666 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
667 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
668 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
669 EXPECT_LENW;
671 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
672 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
673 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
674 EXPECT_LENW; EXPECT_EQW;
676 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
677 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
678 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
679 EXPECT_LENW; EXPECT_EQW;
681 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
682 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
683 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
684 EXPECT_LENW; EXPECT_EQW;
686 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
687 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
688 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
689 EXPECT_LENW; EXPECT_EQW;
691 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
692 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
693 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
694 EXPECT_LENW; EXPECT_EQW;
696 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
697 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
698 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
699 EXPECT_LENW; EXPECT_EQW;
701 STRINGSW("t/tt", "A/AM"); /* AM time marker */
702 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
703 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
704 EXPECT_LENW; EXPECT_EQW;
706 curtime.wHour = 13;
707 STRINGSW("t/tt", "P/PM"); /* PM time marker */
708 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
709 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
710 EXPECT_LENW; EXPECT_EQW;
712 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
713 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
715 EXPECT_LENW; EXPECT_EQW;
717 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
718 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
719 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
720 EXPECT_LENW; EXPECT_EQW;
722 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
723 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
724 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
725 EXPECT_LENW; EXPECT_EQW;
727 curtime.wHour = 14; /* change this to 14 or 2pm */
728 curtime.wMinute = 5;
729 curtime.wSecond = 3;
730 STRINGSW("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
731 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
732 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
733 EXPECT_LENW; EXPECT_EQW;
735 curtime.wHour = 0;
736 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
737 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
738 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
739 EXPECT_LENW; EXPECT_EQW;
741 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
742 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
743 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
744 EXPECT_LENW; EXPECT_EQW;
746 /* try to convert formatting strings with more than two letters
747 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
748 * NOTE: We expect any letter for which there is an upper case value
749 * we should see a replacement. For letters that DO NOT have
750 * upper case values we should see NO REPLACEMENT.
752 curtime.wHour = 8;
753 curtime.wMinute = 56;
754 curtime.wSecond = 13;
755 curtime.wMilliseconds = 22;
756 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
757 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
758 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
759 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
760 EXPECT_LENW; EXPECT_EQW;
762 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
763 lstrcpyW(buffer, Expected);
764 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
765 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
766 EXPECT_EQW;
768 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
769 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
770 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
771 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
772 EXPECT_LENW; EXPECT_EQW;
774 STRINGSW("'''", "'"); /* invalid quoted string */
775 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
776 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
777 EXPECT_LENW; EXPECT_EQW;
779 /* test that msdn suggested single quotation usage works as expected */
780 STRINGSW("''''", "'"); /* single quote mark */
781 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
782 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
783 EXPECT_LENW; EXPECT_EQW;
785 STRINGSW("''HHHHHH", "08"); /* Normal use */
786 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
787 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
788 EXPECT_LENW; EXPECT_EQW;
790 /* and test for normal use of the single quotation mark */
791 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
792 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
793 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
794 EXPECT_LENW; EXPECT_EQW;
796 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
797 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
798 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
799 EXPECT_LENW; EXPECT_EQW;
801 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
802 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
803 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
804 EXPECT_LENW; EXPECT_EQW;
806 curtime.wHour = 25;
807 STRINGSW("'123'tt", ""); /* Invalid time */
808 SetLastError(0xdeadbeef);
809 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
810 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
811 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
813 curtime.wHour = 12;
814 curtime.wMonth = 60; /* Invalid */
815 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
816 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
817 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
818 EXPECT_LENW; EXPECT_EQW;
821 static void test_GetDateFormatA(void)
823 int ret;
824 SYSTEMTIME curtime;
825 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
826 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
827 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
828 char Broken[BUFFER_SIZE];
829 char short_day[10], month[10], genitive_month[10];
831 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
832 STRINGSA("ddd',' MMM dd yy","");
833 SetLastError(0xdeadbeef);
834 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
835 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
836 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
838 curtime.wYear = 2002;
839 curtime.wMonth = 5;
840 curtime.wDay = 4;
841 curtime.wDayOfWeek = 3;
842 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
843 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
844 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
845 EXPECT_LENA; EXPECT_EQA;
847 /* Same as above but with LOCALE_NOUSEROVERRIDE */
848 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
849 SetLastError(0xdeadbeef);
850 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
851 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
852 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
853 EXPECT_EQA;
855 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
856 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
857 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
858 EXPECT_LENA; EXPECT_EQA;
860 curtime.wHour = 36; /* Invalid */
861 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
862 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
863 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
864 EXPECT_LENA; EXPECT_EQA;
866 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
867 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
868 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
869 EXPECT_EQA;
871 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
872 SetLastError(0xdeadbeef);
873 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
874 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
875 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
877 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
878 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
879 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
880 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
881 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
883 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
884 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
885 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
886 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
887 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
888 "got an unexpected date string '%s'\n", buffer);
890 /* test for expected DATE_YEARMONTH behavior with null format */
891 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
892 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
893 SetLastError(0xdeadbeef);
894 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
895 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
896 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
897 EXPECT_EQA;
899 /* Test that using invalid DATE_* flags results in the correct error */
900 /* and return values */
901 STRINGSA("m/d/y", ""); /* Invalid flags */
902 SetLastError(0xdeadbeef);
903 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
904 &curtime, input, buffer, COUNTOF(buffer));
905 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
906 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
908 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
909 if (!ret)
911 win_skip("LANG_RUSSIAN locale data unavailable\n");
912 return;
915 /* month part should be in genitive form */
916 strcpy(genitive_month, buffer + 2);
917 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
918 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919 strcpy(month, buffer);
920 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
922 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
923 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
924 strcpy(short_day, buffer);
926 STRINGSA("dd MMMMddd dd", "");
927 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
928 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
929 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
930 EXPECT_EQA;
932 STRINGSA("MMMMddd dd", "");
933 sprintf(Expected, "%s%s 04", month, short_day);
934 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
935 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
936 EXPECT_EQA;
938 STRINGSA("MMMMddd", "");
939 sprintf(Expected, "%s%s", month, short_day);
940 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
941 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
942 EXPECT_EQA;
944 STRINGSA("MMMMdd", "");
945 sprintf(Expected, "%s04", genitive_month);
946 sprintf(Broken, "%s04", month);
947 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
948 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
949 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
950 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
951 "Expected '%s', got '%s'\n", Expected, buffer);
953 STRINGSA("MMMMdd ddd", "");
954 sprintf(Expected, "%s04 %s", genitive_month, short_day);
955 sprintf(Broken, "%s04 %s", month, short_day);
956 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
957 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
958 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
959 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
960 "Expected '%s', got '%s'\n", Expected, buffer);
962 STRINGSA("dd dddMMMM", "");
963 sprintf(Expected, "04 %s%s", short_day, month);
964 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
965 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
966 EXPECT_EQA;
968 STRINGSA("dd dddMMMM ddd MMMMdd", "");
969 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
970 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
971 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
972 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
973 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
974 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
975 "Expected '%s', got '%s'\n", Expected, buffer);
977 /* with literal part */
978 STRINGSA("ddd',' MMMM dd", "");
979 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
980 sprintf(Broken, "%s, %s 04", short_day, month);
981 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
982 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
983 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
984 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
985 "Expected '%s', got '%s'\n", Expected, buffer);
988 static void test_GetDateFormatEx(void)
990 int ret;
991 SYSTEMTIME curtime;
992 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
994 if (!pGetDateFormatEx)
996 win_skip("GetDateFormatEx not supported\n");
997 return;
1000 STRINGSW("",""); /* If flags are set, then format must be NULL */
1001 SetLastError(0xdeadbeef);
1002 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1003 input, buffer, COUNTOF(buffer), NULL);
1004 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1005 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1006 EXPECT_EQW;
1008 STRINGSW("",""); /* NULL buffer, len > 0 */
1009 SetLastError(0xdeadbeef);
1010 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1011 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1012 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1014 STRINGSW("",""); /* NULL buffer, len == 0 */
1015 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1016 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1017 EXPECT_LENW; EXPECT_EQW;
1019 STRINGSW("",""); /* Invalid flag combination */
1020 SetLastError(0xdeadbeef);
1021 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1022 input, NULL, 0, NULL);
1023 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1024 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1025 EXPECT_EQW;
1027 curtime.wYear = 2002;
1028 curtime.wMonth = 10;
1029 curtime.wDay = 23;
1030 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1031 curtime.wHour = 65432; /* Invalid */
1032 curtime.wMinute = 34512; /* Invalid */
1033 curtime.wSecond = 65535; /* Invalid */
1034 curtime.wMilliseconds = 12345;
1035 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1036 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1037 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1038 EXPECT_LENW; EXPECT_EQW;
1040 curtime.wYear = 2002;
1041 curtime.wMonth = 10;
1042 curtime.wDay = 23;
1043 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1044 curtime.wHour = 65432; /* Invalid */
1045 curtime.wMinute = 34512; /* Invalid */
1046 curtime.wSecond = 65535; /* Invalid */
1047 curtime.wMilliseconds = 12345;
1048 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1049 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1050 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1051 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1053 /* Limit tests */
1055 curtime.wYear = 1601;
1056 curtime.wMonth = 1;
1057 curtime.wDay = 1;
1058 curtime.wDayOfWeek = 0; /* Irrelevant */
1059 curtime.wHour = 0;
1060 curtime.wMinute = 0;
1061 curtime.wSecond = 0;
1062 curtime.wMilliseconds = 0;
1063 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1064 SetLastError(0xdeadbeef);
1065 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1066 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1067 EXPECT_LENW; EXPECT_EQW;
1069 curtime.wYear = 1600;
1070 curtime.wMonth = 12;
1071 curtime.wDay = 31;
1072 curtime.wDayOfWeek = 0; /* Irrelevant */
1073 curtime.wHour = 23;
1074 curtime.wMinute = 59;
1075 curtime.wSecond = 59;
1076 curtime.wMilliseconds = 999;
1077 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1078 SetLastError(0xdeadbeef);
1079 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1080 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1081 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1084 static void test_GetDateFormatW(void)
1086 int ret;
1087 SYSTEMTIME curtime;
1088 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1089 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1091 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1092 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1093 input, buffer, COUNTOF(buffer));
1094 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1096 win_skip("GetDateFormatW is not implemented\n");
1097 return;
1099 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1100 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1101 EXPECT_EQW;
1103 STRINGSW("",""); /* NULL buffer, len > 0 */
1104 SetLastError(0xdeadbeef);
1105 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1106 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1107 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1109 STRINGSW("",""); /* NULL buffer, len == 0 */
1110 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1111 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1112 EXPECT_LENW; EXPECT_EQW;
1114 curtime.wYear = 2002;
1115 curtime.wMonth = 10;
1116 curtime.wDay = 23;
1117 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1118 curtime.wHour = 65432; /* Invalid */
1119 curtime.wMinute = 34512; /* Invalid */
1120 curtime.wSecond = 65535; /* Invalid */
1121 curtime.wMilliseconds = 12345;
1122 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1123 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1124 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1125 EXPECT_LENW; EXPECT_EQW;
1127 /* Limit tests */
1129 curtime.wYear = 1601;
1130 curtime.wMonth = 1;
1131 curtime.wDay = 1;
1132 curtime.wDayOfWeek = 0; /* Irrelevant */
1133 curtime.wHour = 0;
1134 curtime.wMinute = 0;
1135 curtime.wSecond = 0;
1136 curtime.wMilliseconds = 0;
1137 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1138 SetLastError(0xdeadbeef);
1139 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1140 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1141 EXPECT_LENW; EXPECT_EQW;
1143 curtime.wYear = 1600;
1144 curtime.wMonth = 12;
1145 curtime.wDay = 31;
1146 curtime.wDayOfWeek = 0; /* Irrelevant */
1147 curtime.wHour = 23;
1148 curtime.wMinute = 59;
1149 curtime.wSecond = 59;
1150 curtime.wMilliseconds = 999;
1151 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1152 SetLastError(0xdeadbeef);
1153 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1154 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1155 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1159 #define CY_POS_LEFT 0
1160 #define CY_POS_RIGHT 1
1161 #define CY_POS_LEFT_SPACE 2
1162 #define CY_POS_RIGHT_SPACE 3
1164 static void test_GetCurrencyFormatA(void)
1166 static char szDot[] = { '.', '\0' };
1167 static char szComma[] = { ',', '\0' };
1168 static char szDollar[] = { '$', '\0' };
1169 int ret;
1170 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1171 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1172 CURRENCYFMTA format;
1174 memset(&format, 0, sizeof(format));
1176 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1177 SetLastError(0xdeadbeef);
1178 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1179 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1180 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1182 STRINGSA("23,53",""); /* Invalid character --> Error */
1183 SetLastError(0xdeadbeef);
1184 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1185 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1186 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1188 STRINGSA("--",""); /* Double '-' --> Error */
1189 SetLastError(0xdeadbeef);
1190 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1191 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1192 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1194 STRINGSA("0-",""); /* Trailing '-' --> Error */
1195 SetLastError(0xdeadbeef);
1196 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1197 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1198 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1200 STRINGSA("0..",""); /* Double '.' --> Error */
1201 SetLastError(0xdeadbeef);
1202 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1203 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1204 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1206 STRINGSA(" 0.1",""); /* Leading space --> Error */
1207 SetLastError(0xdeadbeef);
1208 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1209 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1210 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1212 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1213 SetLastError(0xdeadbeef);
1214 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1215 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1216 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1218 STRINGSA("2353",""); /* Format and flags given --> Error */
1219 SetLastError(0xdeadbeef);
1220 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1221 ok( !ret, "Expected ret == 0, got %d\n", ret);
1222 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1223 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1225 STRINGSA("2353",""); /* Invalid format --> Error */
1226 SetLastError(0xdeadbeef);
1227 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1228 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1229 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1231 STRINGSA("2353","$2,353.00"); /* Valid number */
1232 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1233 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1234 EXPECT_LENA; EXPECT_EQA;
1236 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1237 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1238 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1239 EXPECT_LENA; EXPECT_EQA;
1241 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1242 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1243 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1244 EXPECT_LENA; EXPECT_EQA;
1246 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1247 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1248 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1249 EXPECT_LENA; EXPECT_EQA;
1251 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1252 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1253 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1254 EXPECT_LENA; EXPECT_EQA;
1256 format.NumDigits = 0; /* No decimal separator */
1257 format.LeadingZero = 0;
1258 format.Grouping = 0; /* No grouping char */
1259 format.NegativeOrder = 0;
1260 format.PositiveOrder = CY_POS_LEFT;
1261 format.lpDecimalSep = szDot;
1262 format.lpThousandSep = szComma;
1263 format.lpCurrencySymbol = szDollar;
1265 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1266 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1267 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1268 EXPECT_LENA; EXPECT_EQA;
1270 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1271 STRINGSA("2353","$2353.0");
1272 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1273 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1274 EXPECT_LENA; EXPECT_EQA;
1276 format.Grouping = 2; /* Group by 100's */
1277 STRINGSA("2353","$23,53.0");
1278 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1279 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1280 EXPECT_LENA; EXPECT_EQA;
1282 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1283 format.Grouping = 3;
1284 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1285 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1286 EXPECT_LENA; EXPECT_EQA;
1288 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1289 format.NegativeOrder = 2;
1290 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1291 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1292 EXPECT_LENA; EXPECT_EQA;
1294 format.LeadingZero = 1; /* Always provide leading zero */
1295 STRINGSA(".5","$0.5");
1296 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1297 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1298 EXPECT_LENA; EXPECT_EQA;
1300 format.PositiveOrder = CY_POS_RIGHT;
1301 STRINGSA("1","1.0$");
1302 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1303 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1304 EXPECT_LENA; EXPECT_EQA;
1306 format.PositiveOrder = CY_POS_LEFT_SPACE;
1307 STRINGSA("1","$ 1.0");
1308 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1309 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1310 EXPECT_LENA; EXPECT_EQA;
1312 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1313 STRINGSA("1","1.0 $");
1314 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1315 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1316 EXPECT_LENA; EXPECT_EQA;
1318 format.NegativeOrder = 0;
1319 STRINGSA("-1","($1.0)");
1320 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1321 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1322 EXPECT_LENA; EXPECT_EQA;
1324 format.NegativeOrder = 1;
1325 STRINGSA("-1","-$1.0");
1326 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1327 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1328 EXPECT_LENA; EXPECT_EQA;
1330 format.NegativeOrder = 2;
1331 STRINGSA("-1","$-1.0");
1332 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1333 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1334 EXPECT_LENA; EXPECT_EQA;
1336 format.NegativeOrder = 3;
1337 STRINGSA("-1","$1.0-");
1338 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1339 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1340 EXPECT_LENA; EXPECT_EQA;
1342 format.NegativeOrder = 4;
1343 STRINGSA("-1","(1.0$)");
1344 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1345 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1346 EXPECT_LENA; EXPECT_EQA;
1348 format.NegativeOrder = 5;
1349 STRINGSA("-1","-1.0$");
1350 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1351 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1352 EXPECT_LENA; EXPECT_EQA;
1354 format.NegativeOrder = 6;
1355 STRINGSA("-1","1.0-$");
1356 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1357 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1358 EXPECT_LENA; EXPECT_EQA;
1360 format.NegativeOrder = 7;
1361 STRINGSA("-1","1.0$-");
1362 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1363 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1364 EXPECT_LENA; EXPECT_EQA;
1366 format.NegativeOrder = 8;
1367 STRINGSA("-1","-1.0 $");
1368 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1369 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1370 EXPECT_LENA; EXPECT_EQA;
1372 format.NegativeOrder = 9;
1373 STRINGSA("-1","-$ 1.0");
1374 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1375 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1376 EXPECT_LENA; EXPECT_EQA;
1378 format.NegativeOrder = 10;
1379 STRINGSA("-1","1.0 $-");
1380 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1381 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1382 EXPECT_LENA; EXPECT_EQA;
1384 format.NegativeOrder = 11;
1385 STRINGSA("-1","$ 1.0-");
1386 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1387 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1388 EXPECT_LENA; EXPECT_EQA;
1390 format.NegativeOrder = 12;
1391 STRINGSA("-1","$ -1.0");
1392 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1393 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1394 EXPECT_LENA; EXPECT_EQA;
1396 format.NegativeOrder = 13;
1397 STRINGSA("-1","1.0- $");
1398 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1399 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1400 EXPECT_LENA; EXPECT_EQA;
1402 format.NegativeOrder = 14;
1403 STRINGSA("-1","($ 1.0)");
1404 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1405 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1406 EXPECT_LENA; EXPECT_EQA;
1408 format.NegativeOrder = 15;
1409 STRINGSA("-1","(1.0 $)");
1410 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1411 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1412 EXPECT_LENA; EXPECT_EQA;
1415 #define NEG_PARENS 0 /* "(1.1)" */
1416 #define NEG_LEFT 1 /* "-1.1" */
1417 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1418 #define NEG_RIGHT 3 /* "1.1-" */
1419 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1421 static void test_GetNumberFormatA(void)
1423 static char szDot[] = { '.', '\0' };
1424 static char szComma[] = { ',', '\0' };
1425 int ret;
1426 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1427 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1428 NUMBERFMTA format;
1430 memset(&format, 0, sizeof(format));
1432 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1433 SetLastError(0xdeadbeef);
1434 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1435 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1436 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1438 STRINGSA("23,53",""); /* Invalid character --> Error */
1439 SetLastError(0xdeadbeef);
1440 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1441 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1442 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1444 STRINGSA("--",""); /* Double '-' --> Error */
1445 SetLastError(0xdeadbeef);
1446 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1447 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1448 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1450 STRINGSA("0-",""); /* Trailing '-' --> Error */
1451 SetLastError(0xdeadbeef);
1452 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1453 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1454 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1456 STRINGSA("0..",""); /* Double '.' --> Error */
1457 SetLastError(0xdeadbeef);
1458 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1459 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1460 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1462 STRINGSA(" 0.1",""); /* Leading space --> Error */
1463 SetLastError(0xdeadbeef);
1464 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1465 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1466 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1468 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1469 SetLastError(0xdeadbeef);
1470 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1471 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1472 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1474 STRINGSA("2353",""); /* Format and flags given --> Error */
1475 SetLastError(0xdeadbeef);
1476 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1477 ok( !ret, "Expected ret == 0, got %d\n", ret);
1478 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1479 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1481 STRINGSA("2353",""); /* Invalid format --> Error */
1482 SetLastError(0xdeadbeef);
1483 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1484 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1485 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1487 STRINGSA("2353","2,353.00"); /* Valid number */
1488 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1489 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1490 EXPECT_LENA; EXPECT_EQA;
1492 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1493 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1494 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1495 EXPECT_LENA; EXPECT_EQA;
1497 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1498 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1499 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1500 EXPECT_LENA; EXPECT_EQA;
1502 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1503 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1504 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1505 EXPECT_LENA; EXPECT_EQA;
1507 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1508 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1509 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1510 EXPECT_LENA; EXPECT_EQA;
1512 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1513 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1514 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1515 EXPECT_LENA; EXPECT_EQA;
1517 format.NumDigits = 0; /* No decimal separator */
1518 format.LeadingZero = 0;
1519 format.Grouping = 0; /* No grouping char */
1520 format.NegativeOrder = 0;
1521 format.lpDecimalSep = szDot;
1522 format.lpThousandSep = szComma;
1524 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1525 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1527 EXPECT_LENA; EXPECT_EQA;
1529 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1530 STRINGSA("2353","2353.0");
1531 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1532 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1533 EXPECT_LENA; EXPECT_EQA;
1535 format.Grouping = 2; /* Group by 100's */
1536 STRINGSA("2353","23,53.0");
1537 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1538 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1539 EXPECT_LENA; EXPECT_EQA;
1541 STRINGSA("235","235.0"); /* Grouping of a positive number */
1542 format.Grouping = 3;
1543 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1544 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1545 EXPECT_LENA; EXPECT_EQA;
1547 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1548 format.NegativeOrder = NEG_LEFT;
1549 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1550 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1551 EXPECT_LENA; EXPECT_EQA;
1553 format.LeadingZero = 1; /* Always provide leading zero */
1554 STRINGSA(".5","0.5");
1555 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1556 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1557 EXPECT_LENA; EXPECT_EQA;
1559 format.NegativeOrder = NEG_PARENS;
1560 STRINGSA("-1","(1.0)");
1561 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1562 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1563 EXPECT_LENA; EXPECT_EQA;
1565 format.NegativeOrder = NEG_LEFT;
1566 STRINGSA("-1","-1.0");
1567 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1568 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1569 EXPECT_LENA; EXPECT_EQA;
1571 format.NegativeOrder = NEG_LEFT_SPACE;
1572 STRINGSA("-1","- 1.0");
1573 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1574 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1575 EXPECT_LENA; EXPECT_EQA;
1577 format.NegativeOrder = NEG_RIGHT;
1578 STRINGSA("-1","1.0-");
1579 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1580 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1581 EXPECT_LENA; EXPECT_EQA;
1583 format.NegativeOrder = NEG_RIGHT_SPACE;
1584 STRINGSA("-1","1.0 -");
1585 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1586 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1587 EXPECT_LENA; EXPECT_EQA;
1589 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1591 if (IsValidLocale(lcid, 0))
1593 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1594 Expected[3] = 160; /* Non breaking space */
1595 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1596 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1597 EXPECT_LENA; EXPECT_EQA;
1601 static void test_GetNumberFormatEx(void)
1603 int ret;
1604 NUMBERFMTW format;
1605 static WCHAR dotW[] = {'.',0};
1606 static WCHAR commaW[] = {',',0};
1607 static const WCHAR enW[] = {'e','n','-','U','S',0};
1608 static const WCHAR frW[] = {'f','r','-','F','R',0};
1609 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1610 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1612 if (!pGetNumberFormatEx)
1614 win_skip("GetNumberFormatEx is not available.\n");
1615 return;
1618 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1619 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1620 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1621 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1623 STRINGSW("23,53",""); /* Invalid character --> Error */
1624 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1625 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1626 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1628 STRINGSW("--",""); /* Double '-' --> Error */
1629 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1630 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1631 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1633 STRINGSW("0-",""); /* Trailing '-' --> Error */
1634 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1635 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1636 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1638 STRINGSW("0..",""); /* Double '.' --> Error */
1639 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1640 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1641 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1643 STRINGSW(" 0.1",""); /* Leading space --> Error */
1644 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1645 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1646 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1648 STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1649 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1650 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1651 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1653 STRINGSW("23",""); /* Bogus locale --> Error */
1654 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1655 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1656 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1658 memset(&format, 0, sizeof(format));
1660 STRINGSW("2353",""); /* Format and flags given --> Error */
1661 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1662 ok( !ret, "Expected ret == 0, got %d\n", ret);
1663 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1664 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1666 STRINGSW("2353",""); /* Invalid format --> Error */
1667 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1668 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1669 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1671 STRINGSW("2353","2,353.00"); /* Valid number */
1672 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1673 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1674 EXPECT_LENW; EXPECT_EQW;
1676 STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1677 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1678 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1679 EXPECT_LENW; EXPECT_EQW;
1681 STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1682 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1683 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1684 EXPECT_LENW; EXPECT_EQW;
1686 STRINGSW("2353.1","2,353.10"); /* Valid real number */
1687 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1688 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1689 EXPECT_LENW; EXPECT_EQW;
1691 STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1692 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1693 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1694 EXPECT_LENW; EXPECT_EQW;
1696 STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */
1697 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1698 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1699 EXPECT_LENW; EXPECT_EQW;
1701 format.NumDigits = 0; /* No decimal separator */
1702 format.LeadingZero = 0;
1703 format.Grouping = 0; /* No grouping char */
1704 format.NegativeOrder = 0;
1705 format.lpDecimalSep = dotW;
1706 format.lpThousandSep = commaW;
1708 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1709 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1710 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1711 EXPECT_LENW; EXPECT_EQW;
1713 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1714 STRINGSW("2353","2353.0");
1715 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1716 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1717 EXPECT_LENW; EXPECT_EQW;
1719 format.Grouping = 2; /* Group by 100's */
1720 STRINGSW("2353","23,53.0");
1721 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1722 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1723 EXPECT_LENW; EXPECT_EQW;
1725 STRINGSW("235","235.0"); /* Grouping of a positive number */
1726 format.Grouping = 3;
1727 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1728 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1729 EXPECT_LENW; EXPECT_EQW;
1731 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1732 format.NegativeOrder = NEG_LEFT;
1733 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1734 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1735 EXPECT_LENW; EXPECT_EQW;
1737 format.LeadingZero = 1; /* Always provide leading zero */
1738 STRINGSW(".5","0.5");
1739 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1740 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1741 EXPECT_LENW; EXPECT_EQW;
1743 format.NegativeOrder = NEG_PARENS;
1744 STRINGSW("-1","(1.0)");
1745 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1746 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1747 EXPECT_LENW; EXPECT_EQW;
1749 format.NegativeOrder = NEG_LEFT;
1750 STRINGSW("-1","-1.0");
1751 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1752 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1753 EXPECT_LENW; EXPECT_EQW;
1755 format.NegativeOrder = NEG_LEFT_SPACE;
1756 STRINGSW("-1","- 1.0");
1757 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1758 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1759 EXPECT_LENW; EXPECT_EQW;
1761 format.NegativeOrder = NEG_RIGHT;
1762 STRINGSW("-1","1.0-");
1763 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1764 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1765 EXPECT_LENW; EXPECT_EQW;
1767 format.NegativeOrder = NEG_RIGHT_SPACE;
1768 STRINGSW("-1","1.0 -");
1769 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1770 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1771 EXPECT_LENW; EXPECT_EQW;
1773 if (pIsValidLocaleName(frW))
1775 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1776 Expected[3] = 160; /* Non breaking space */
1777 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1778 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1779 EXPECT_LENW; EXPECT_EQW;
1783 struct comparestringa_entry {
1784 LCID lcid;
1785 DWORD flags;
1786 const char *first;
1787 int first_len;
1788 const char *second;
1789 int second_len;
1790 int ret;
1793 static const struct comparestringa_entry comparestringa_data[] = {
1794 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1797 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1798 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1799 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1808 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1809 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1810 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1811 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1812 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1813 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1814 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1818 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1820 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1821 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1823 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1824 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1825 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1826 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1827 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1828 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1833 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1834 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1835 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1836 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1837 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1840 static void test_CompareStringA(void)
1842 int ret, i;
1843 char a[256];
1844 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1846 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1848 const struct comparestringa_entry *entry = &comparestringa_data[i];
1850 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1851 entry->second, entry->second_len);
1852 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1855 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1856 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1858 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1859 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1861 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1862 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1864 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1865 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1867 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1869 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1870 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1872 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1873 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1875 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1876 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1878 /* test for CompareStringA flags */
1879 SetLastError(0xdeadbeef);
1880 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1881 ok(GetLastError() == ERROR_INVALID_FLAGS,
1882 "unexpected error code %d\n", GetLastError());
1883 ok(!ret, "CompareStringA must fail with invalid flag\n");
1885 SetLastError(0xdeadbeef);
1886 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1887 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1888 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1889 /* end of test for CompareStringA flags */
1891 ret = lstrcmpA("", "");
1892 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1894 ret = lstrcmpA(NULL, NULL);
1895 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1897 ret = lstrcmpA("", NULL);
1898 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1900 ret = lstrcmpA(NULL, "");
1901 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1904 if (0) { /* this requires collation table patch to make it MS compatible */
1905 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1906 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1908 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1909 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1911 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1912 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1914 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1915 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1917 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1918 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1920 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1921 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1923 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1924 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1926 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1927 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1929 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1930 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1932 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1933 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1935 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1936 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1938 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1939 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1943 /* WinXP handles embedded NULLs differently than earlier versions */
1944 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1945 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1947 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1948 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);
1950 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1951 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1953 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1954 ok(ret == CSTR_EQUAL || /* win2k */
1955 ret == CSTR_GREATER_THAN,
1956 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1958 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1959 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1961 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1962 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1964 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1965 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1967 ret = lstrcmpiA("#", ".");
1968 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1970 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1972 /* \xB9 character lies between a and b */
1973 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1974 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1975 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1976 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1978 memset(a, 'a', sizeof(a));
1979 SetLastError(0xdeadbeef);
1980 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1981 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1982 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1985 static void test_CompareStringW(void)
1987 WCHAR *str1, *str2;
1988 SYSTEM_INFO si;
1989 DWORD old_prot;
1990 BOOL success;
1991 char *buf;
1992 int ret;
1994 GetSystemInfo(&si);
1995 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1996 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1997 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1998 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1999 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2000 ok(success, "VirtualProtect failed with %u\n", GetLastError());
2002 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2003 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2004 *str1 = 'A';
2005 *str2 = 'B';
2007 /* CompareStringW should abort on the first non-matching character */
2008 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2009 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2011 success = VirtualFree(buf, 0, MEM_RELEASE);
2012 ok(success, "VirtualFree failed with %u\n", GetLastError());
2015 struct comparestringex_test {
2016 const char *locale;
2017 DWORD flags;
2018 const WCHAR first[2];
2019 const WCHAR second[2];
2020 INT ret;
2021 INT broken;
2022 BOOL todo;
2025 static const struct comparestringex_test comparestringex_tests[] = {
2026 /* default behavior */
2027 { /* 0 */
2028 "tr-TR", 0,
2029 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2031 { /* 1 */
2032 "tr-TR", 0,
2033 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2035 { /* 2 */
2036 "tr-TR", 0,
2037 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2039 { /* 3 */
2040 "tr-TR", 0,
2041 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2043 { /* 4 */
2044 "tr-TR", 0,
2045 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2047 { /* 5 */
2048 "tr-TR", 0,
2049 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2051 /* with NORM_IGNORECASE */
2052 { /* 6 */
2053 "tr-TR", NORM_IGNORECASE,
2054 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2056 { /* 7 */
2057 "tr-TR", NORM_IGNORECASE,
2058 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2060 { /* 8 */
2061 "tr-TR", NORM_IGNORECASE,
2062 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2064 { /* 9 */
2065 "tr-TR", NORM_IGNORECASE,
2066 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2068 { /* 10 */
2069 "tr-TR", NORM_IGNORECASE,
2070 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2072 { /* 11 */
2073 "tr-TR", NORM_IGNORECASE,
2074 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2076 /* with NORM_LINGUISTIC_CASING */
2077 { /* 12 */
2078 "tr-TR", NORM_LINGUISTIC_CASING,
2079 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2081 { /* 13 */
2082 "tr-TR", NORM_LINGUISTIC_CASING,
2083 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2085 { /* 14 */
2086 "tr-TR", NORM_LINGUISTIC_CASING,
2087 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2089 { /* 15 */
2090 "tr-TR", NORM_LINGUISTIC_CASING,
2091 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2093 { /* 16 */
2094 "tr-TR", NORM_LINGUISTIC_CASING,
2095 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2097 { /* 17 */
2098 "tr-TR", NORM_LINGUISTIC_CASING,
2099 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2101 /* with LINGUISTIC_IGNORECASE */
2102 { /* 18 */
2103 "tr-TR", LINGUISTIC_IGNORECASE,
2104 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2106 { /* 19 */
2107 "tr-TR", LINGUISTIC_IGNORECASE,
2108 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2110 { /* 20 */
2111 "tr-TR", LINGUISTIC_IGNORECASE,
2112 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2114 { /* 21 */
2115 "tr-TR", LINGUISTIC_IGNORECASE,
2116 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2118 { /* 22 */
2119 "tr-TR", LINGUISTIC_IGNORECASE,
2120 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2122 { /* 23 */
2123 "tr-TR", LINGUISTIC_IGNORECASE,
2124 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2126 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2127 { /* 24 */
2128 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2129 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2131 { /* 25 */
2132 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2133 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2135 { /* 26 */
2136 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2137 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2139 { /* 27 */
2140 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2141 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2143 { /* 28 */
2144 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2145 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2147 { /* 29 */
2148 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2149 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2151 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2152 { /* 30 */
2153 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2154 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2156 { /* 31 */
2157 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2158 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2160 { /* 32 */
2161 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2162 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2164 { /* 33 */
2165 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2166 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2168 { /* 34 */
2169 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2170 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2172 { /* 35 */
2173 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2174 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2178 static void test_CompareStringEx(void)
2180 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2181 WCHAR locale[6];
2182 INT ret, i;
2184 /* CompareStringEx is only available on Vista+ */
2185 if (!pCompareStringEx)
2187 win_skip("CompareStringEx not supported\n");
2188 return;
2191 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2193 const struct comparestringex_test *e = &comparestringex_tests[i];
2195 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2196 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2197 todo_wine_if (e->todo)
2198 ok(ret == e->ret || broken(ret == e->broken),
2199 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2204 static const DWORD lcmap_invalid_flags[] = {
2206 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2207 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2208 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2209 LCMAP_LOWERCASE | SORT_STRINGSORT,
2210 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2211 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2212 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2213 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2214 LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2215 LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2216 LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2217 LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2218 LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2219 LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2220 LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2221 LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2222 LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2223 LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2224 LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2225 LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2226 LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2227 LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2228 LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2229 LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2232 static void test_LCMapStringA(void)
2234 int ret, ret2, i;
2235 char buf[256], buf2[256];
2236 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2237 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2238 static const char symbols_stripped[] = "justateststring1";
2240 SetLastError(0xdeadbeef);
2241 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2242 lower_case, -1, buf, sizeof(buf));
2243 ok(ret == lstrlenA(lower_case) + 1,
2244 "ret %d, error %d, expected value %d\n",
2245 ret, GetLastError(), lstrlenA(lower_case) + 1);
2246 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2248 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2249 upper_case, -1, buf, sizeof(buf));
2250 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2251 ok(GetLastError() == ERROR_INVALID_FLAGS,
2252 "unexpected error code %d\n", GetLastError());
2254 /* test invalid flag combinations */
2255 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2256 lstrcpyA(buf, "foo");
2257 SetLastError(0xdeadbeef);
2258 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2259 lower_case, -1, buf, sizeof(buf));
2260 ok(GetLastError() == ERROR_INVALID_FLAGS,
2261 "LCMapStringA (flag %08x) unexpected error code %d\n",
2262 lcmap_invalid_flags[i], GetLastError());
2263 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2264 lcmap_invalid_flags[i], ret);
2267 /* test LCMAP_LOWERCASE */
2268 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2269 upper_case, -1, buf, sizeof(buf));
2270 ok(ret == lstrlenA(upper_case) + 1,
2271 "ret %d, error %d, expected value %d\n",
2272 ret, GetLastError(), lstrlenA(upper_case) + 1);
2273 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2275 /* test LCMAP_UPPERCASE */
2276 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2277 lower_case, -1, buf, sizeof(buf));
2278 ok(ret == lstrlenA(lower_case) + 1,
2279 "ret %d, error %d, expected value %d\n",
2280 ret, GetLastError(), lstrlenA(lower_case) + 1);
2281 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2283 /* test buffer overflow */
2284 SetLastError(0xdeadbeef);
2285 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2286 lower_case, -1, buf, 4);
2287 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2288 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2290 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2291 lstrcpyA(buf, lower_case);
2292 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2293 buf, -1, buf, sizeof(buf));
2294 if (!ret) /* Win9x */
2295 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2296 else
2298 ok(ret == lstrlenA(lower_case) + 1,
2299 "ret %d, error %d, expected value %d\n",
2300 ret, GetLastError(), lstrlenA(lower_case) + 1);
2301 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2303 lstrcpyA(buf, upper_case);
2304 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2305 buf, -1, buf, sizeof(buf));
2306 if (!ret) /* Win9x */
2307 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2308 else
2310 ok(ret == lstrlenA(upper_case) + 1,
2311 "ret %d, error %d, expected value %d\n",
2312 ret, GetLastError(), lstrlenA(lower_case) + 1);
2313 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2316 /* otherwise src == dst should fail */
2317 SetLastError(0xdeadbeef);
2318 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2319 buf, 10, buf, sizeof(buf));
2320 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2321 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2322 "unexpected error code %d\n", GetLastError());
2323 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2325 /* test whether '\0' is always appended */
2326 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2327 upper_case, -1, buf, sizeof(buf));
2328 ok(ret, "LCMapStringA must succeed\n");
2329 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2330 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2331 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2332 ok(ret2, "LCMapStringA must succeed\n");
2333 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2334 ok(ret == ret2, "lengths of sort keys must be equal\n");
2335 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2337 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2338 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2339 upper_case, -1, buf, sizeof(buf));
2340 ok(ret, "LCMapStringA must succeed\n");
2341 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2342 lower_case, -1, buf2, sizeof(buf2));
2343 ok(ret2, "LCMapStringA must succeed\n");
2344 ok(ret == ret2, "lengths of sort keys must be equal\n");
2345 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2347 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2348 results from plain LCMAP_SORTKEY on Vista */
2350 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2351 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2352 lower_case, -1, buf, sizeof(buf));
2353 ok(ret, "LCMapStringA must succeed\n");
2354 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2355 symbols_stripped, -1, buf2, sizeof(buf2));
2356 ok(ret2, "LCMapStringA must succeed\n");
2357 ok(ret == ret2, "lengths of sort keys must be equal\n");
2358 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2360 /* test NORM_IGNORENONSPACE */
2361 lstrcpyA(buf, "foo");
2362 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2363 lower_case, -1, buf, sizeof(buf));
2364 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2365 lstrlenA(lower_case) + 1, ret);
2366 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2368 /* test NORM_IGNORESYMBOLS */
2369 lstrcpyA(buf, "foo");
2370 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2371 lower_case, -1, buf, sizeof(buf));
2372 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2373 lstrlenA(symbols_stripped) + 1, ret);
2374 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2376 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2377 lstrcpyA(buf, "foo");
2378 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2379 lower_case, -1, buf, sizeof(buf));
2380 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2381 lstrlenA(symbols_stripped) + 1, ret);
2382 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2384 /* test srclen = 0 */
2385 SetLastError(0xdeadbeef);
2386 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2387 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2388 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2389 "unexpected error code %d\n", GetLastError());
2392 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2394 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2396 const static WCHAR japanese_text[] = {
2397 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2398 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2400 const static WCHAR hiragana_text[] = {
2401 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2402 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2404 const static WCHAR katakana_text[] = {
2405 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2406 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2408 const static WCHAR halfwidth_text[] = {
2409 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2410 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2412 int ret, ret2, i;
2413 WCHAR buf[256], buf2[256];
2414 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2416 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2417 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2418 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2419 todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2420 "%s ret %d, error %d, expected value %d\n", func_name,
2421 ret, GetLastError(), lstrlenW(title_case) + 1);
2422 todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2423 "Expected title case string\n");
2425 /* test invalid flag combinations */
2426 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2427 lstrcpyW(buf, fooW);
2428 SetLastError(0xdeadbeef);
2429 ret = func_ptr(lcmap_invalid_flags[i],
2430 lower_case, -1, buf, sizeof(buf));
2431 ok(GetLastError() == ERROR_INVALID_FLAGS,
2432 "%s (flag %08x) unexpected error code %d\n",
2433 func_name, lcmap_invalid_flags[i], GetLastError());
2434 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2435 func_name, lcmap_invalid_flags[i], ret);
2438 /* test LCMAP_LOWERCASE */
2439 ret = func_ptr(LCMAP_LOWERCASE,
2440 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2441 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2442 ret, GetLastError(), lstrlenW(upper_case) + 1);
2443 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2445 /* test LCMAP_UPPERCASE */
2446 ret = func_ptr(LCMAP_UPPERCASE,
2447 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2448 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2449 ret, GetLastError(), lstrlenW(lower_case) + 1);
2450 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2452 /* test LCMAP_HIRAGANA */
2453 ret = func_ptr(LCMAP_HIRAGANA,
2454 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2455 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2456 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2457 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2459 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2460 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2461 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2462 ret, GetLastError());
2463 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2464 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2465 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2467 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2468 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
2469 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2470 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2471 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2472 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2474 /* test LCMAP_FULLWIDTH */
2475 ret = func_ptr(LCMAP_FULLWIDTH,
2476 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2477 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2478 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2479 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2481 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2482 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2484 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2485 (half-width katakana is converted into full-width hiragana) */
2486 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
2487 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2488 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2489 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2490 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2492 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2493 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2495 /* test LCMAP_HALFWIDTH */
2496 ret = func_ptr(LCMAP_HALFWIDTH,
2497 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2498 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2499 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2500 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2502 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2503 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2505 /* test buffer overflow */
2506 SetLastError(0xdeadbeef);
2507 ret = func_ptr(LCMAP_UPPERCASE,
2508 lower_case, -1, buf, 4);
2509 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2510 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2512 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2513 Thus, it requires two WCHARs. */
2514 buf[0] = 0x30ac;
2515 SetLastError(0xdeadbeef);
2516 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2517 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2518 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2520 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2521 lstrcpyW(buf, lower_case);
2522 ret = func_ptr(LCMAP_UPPERCASE,
2523 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2524 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2525 ret, GetLastError(), lstrlenW(lower_case) + 1);
2526 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2528 lstrcpyW(buf, upper_case);
2529 ret = func_ptr(LCMAP_LOWERCASE,
2530 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2531 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2532 ret, GetLastError(), lstrlenW(lower_case) + 1);
2533 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2535 /* otherwise src == dst should fail */
2536 SetLastError(0xdeadbeef);
2537 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2538 buf, 10, buf, sizeof(buf));
2539 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2540 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2541 "%s unexpected error code %d\n", func_name, GetLastError());
2542 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2544 /* test whether '\0' is always appended */
2545 ret = func_ptr(LCMAP_SORTKEY,
2546 upper_case, -1, buf, sizeof(buf));
2547 ok(ret, "%s func_ptr must succeed\n", func_name);
2548 ret2 = func_ptr(LCMAP_SORTKEY,
2549 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2550 ok(ret, "%s func_ptr must succeed\n", func_name);
2551 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2552 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2554 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2555 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2556 upper_case, -1, buf, sizeof(buf));
2557 ok(ret, "%s func_ptr must succeed\n", func_name);
2558 ret2 = func_ptr(LCMAP_SORTKEY,
2559 lower_case, -1, buf2, sizeof(buf2));
2560 ok(ret2, "%s func_ptr must succeed\n", func_name);
2561 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2562 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2564 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2565 results from plain LCMAP_SORTKEY on Vista */
2567 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2568 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2569 lower_case, -1, buf, sizeof(buf));
2570 ok(ret, "%s func_ptr must succeed\n", func_name);
2571 ret2 = func_ptr(LCMAP_SORTKEY,
2572 symbols_stripped, -1, buf2, sizeof(buf2));
2573 ok(ret2, "%s func_ptr must succeed\n", func_name);
2574 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2575 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2577 /* test NORM_IGNORENONSPACE */
2578 lstrcpyW(buf, fooW);
2579 ret = func_ptr(NORM_IGNORENONSPACE,
2580 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2581 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2582 lstrlenW(lower_case) + 1, ret);
2583 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2585 /* test NORM_IGNORESYMBOLS */
2586 lstrcpyW(buf, fooW);
2587 ret = func_ptr(NORM_IGNORESYMBOLS,
2588 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2589 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2590 lstrlenW(symbols_stripped) + 1, ret);
2591 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2593 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2594 lstrcpyW(buf, fooW);
2595 ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2596 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2597 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2598 lstrlenW(symbols_stripped) + 1, ret);
2599 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2601 /* test srclen = 0 */
2602 SetLastError(0xdeadbeef);
2603 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2604 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2605 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2606 "%s unexpected error code %d\n", func_name, GetLastError());
2609 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2611 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2614 static void test_LCMapStringW(void)
2616 int ret;
2617 WCHAR buf[256];
2619 trace("testing LCMapStringW\n");
2621 SetLastError(0xdeadbeef);
2622 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2623 todo_wine {
2624 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2625 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2628 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2631 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2633 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2636 static void test_LCMapStringEx(void)
2638 int ret;
2639 WCHAR buf[256];
2641 if (!pLCMapStringEx)
2643 win_skip( "LCMapStringEx not available\n" );
2644 return;
2647 trace("testing LCMapStringEx\n");
2649 SetLastError(0xdeadbeef);
2650 ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2651 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2652 todo_wine {
2653 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2654 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2657 /* test reserved parameters */
2658 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2659 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2660 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2661 ret, GetLastError(), lstrlenW(upper_case) + 1);
2662 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2664 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2665 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2666 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2667 ret, GetLastError(), lstrlenW(upper_case) + 1);
2668 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2670 /* crashes on native */
2671 if(0)
2672 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2673 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2675 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2678 struct neutralsublang_name_t {
2679 WCHAR name[3];
2680 WCHAR sname[16];
2681 LCID lcid;
2682 int todo;
2685 static const struct neutralsublang_name_t neutralsublang_names[] = {
2686 { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2687 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2688 { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2689 { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2690 { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2691 { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2692 { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2693 { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2694 { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2695 { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2696 { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2697 { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2698 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2699 { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2700 { {0} }
2703 static void test_LocaleNameToLCID(void)
2705 LCID lcid;
2706 INT ret;
2707 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2708 static const WCHAR enW[] = {'e','n',0};
2709 static const WCHAR esesW[] = {'e','s','-','e','s',0};
2710 static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
2711 static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
2712 static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
2713 static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
2714 static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
2715 static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
2717 if (!pLocaleNameToLCID)
2719 win_skip( "LocaleNameToLCID not available\n" );
2720 return;
2723 /* special cases */
2724 buffer[0] = 0;
2725 SetLastError(0xdeadbeef);
2726 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2727 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2728 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2729 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2730 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2731 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2733 buffer[0] = 0;
2734 SetLastError(0xdeadbeef);
2735 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2736 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2737 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2738 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2739 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2740 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2742 buffer[0] = 0;
2743 SetLastError(0xdeadbeef);
2744 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2745 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2746 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2747 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2748 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2750 /* bad name */
2751 SetLastError(0xdeadbeef);
2752 lcid = pLocaleNameToLCID(invalidW, 0);
2753 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2754 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2756 /* lower-case */
2757 lcid = pLocaleNameToLCID(esesW, 0);
2758 ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid);
2760 /* english neutral name */
2761 lcid = pLocaleNameToLCID(enW, 0);
2762 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2763 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2764 if (lcid)
2766 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2768 while (*ptr->name)
2770 lcid = pLocaleNameToLCID(ptr->name, 0);
2771 todo_wine_if (ptr->todo)
2772 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2773 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2775 *buffer = 0;
2776 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2777 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2778 ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
2779 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2781 ptr++;
2784 /* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
2785 lcid = pLocaleNameToLCID(zhHantW, 0);
2786 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2787 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid);
2788 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2789 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2790 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2791 wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2792 /* check that 0x7c04 also works and is mapped to zh-HK */
2793 ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_CHINESE_TRADITIONAL), buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2794 todo_wine ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
2795 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2796 wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
2798 /* zh-hant */
2799 lcid = pLocaleNameToLCID(zhhantW, 0);
2800 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
2801 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW), lcid);
2802 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2803 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret);
2804 ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
2805 wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer));
2807 /* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */
2808 lcid = pLocaleNameToLCID(zhHansW, 0);
2809 /* check that LocaleNameToLCID actually returns 0x0804 */
2810 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2811 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid);
2812 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2813 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2814 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2815 wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2816 /* check that 0x0004 also works and is mapped to zh-CN */
2817 ret = pLCIDToLocaleName(MAKELANGID(LANG_CHINESE, SUBLANG_NEUTRAL), buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2818 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
2819 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2820 wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
2822 /* zh-hans */
2823 lcid = pLocaleNameToLCID(zhhansW, 0);
2824 ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
2825 "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW), lcid);
2826 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2827 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret);
2828 ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
2829 wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
2833 /* this requires collation table patch to make it MS compatible */
2834 static const char * const strings_sorted[] =
2836 "'",
2837 "-",
2838 "!",
2839 "\"",
2840 ".",
2841 ":",
2842 "\\",
2843 "_",
2844 "`",
2845 "{",
2846 "}",
2847 "+",
2848 "0",
2849 "1",
2850 "2",
2851 "3",
2852 "4",
2853 "5",
2854 "6",
2855 "7",
2856 "8",
2857 "9",
2858 "a",
2859 "A",
2860 "b",
2861 "B",
2862 "c",
2866 static const char * const strings[] =
2868 "C",
2869 "\"",
2870 "9",
2871 "'",
2872 "}",
2873 "-",
2874 "7",
2875 "+",
2876 "`",
2877 "1",
2878 "a",
2879 "5",
2880 "\\",
2881 "8",
2882 "B",
2883 "3",
2884 "_",
2885 "6",
2886 "{",
2887 "2",
2888 "c",
2889 "4",
2890 "!",
2891 "0",
2892 "A",
2893 ":",
2894 "b",
2898 static int compare_string1(const void *e1, const void *e2)
2900 const char *s1 = *(const char *const *)e1;
2901 const char *s2 = *(const char *const *)e2;
2903 return lstrcmpA(s1, s2);
2906 static int compare_string2(const void *e1, const void *e2)
2908 const char *s1 = *(const char *const *)e1;
2909 const char *s2 = *(const char *const *)e2;
2911 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2914 static int compare_string3(const void *e1, const void *e2)
2916 const char *s1 = *(const char *const *)e1;
2917 const char *s2 = *(const char *const *)e2;
2918 char key1[256], key2[256];
2920 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2921 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2922 return strcmp(key1, key2);
2925 static void test_sorting(void)
2927 char buf[256];
2928 char **str_buf = (char **)buf;
2929 int i;
2931 assert(sizeof(buf) >= sizeof(strings));
2933 /* 1. sort using lstrcmpA */
2934 memcpy(buf, strings, sizeof(strings));
2935 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2936 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2938 ok(!strcmp(strings_sorted[i], str_buf[i]),
2939 "qsort using lstrcmpA failed for element %d\n", i);
2941 /* 2. sort using CompareStringA */
2942 memcpy(buf, strings, sizeof(strings));
2943 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2944 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2946 ok(!strcmp(strings_sorted[i], str_buf[i]),
2947 "qsort using CompareStringA failed for element %d\n", i);
2949 /* 3. sort using sort keys */
2950 memcpy(buf, strings, sizeof(strings));
2951 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2952 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2954 ok(!strcmp(strings_sorted[i], str_buf[i]),
2955 "qsort using sort keys failed for element %d\n", i);
2959 static void test_FoldStringA(void)
2961 int ret, i, j;
2962 BOOL is_special;
2963 char src[256], dst[256];
2964 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2965 static const char digits_dst[] = { '1','2','3','\0' };
2966 static const char composite_src[] =
2968 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2969 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2970 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2971 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2972 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2973 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2974 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2975 0xfb,0xfc,0xfd,0xff,'\0'
2977 static const char composite_dst[] =
2979 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2980 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2981 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2982 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2983 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2984 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2985 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2986 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2987 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2988 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2989 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2990 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2991 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2992 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2993 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2995 static const char composite_dst_alt[] =
2997 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2998 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2999 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
3000 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
3001 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
3002 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
3003 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
3004 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
3005 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
3006 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
3007 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
3008 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
3009 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
3010 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
3011 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
3013 static const char ligatures_src[] =
3015 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
3017 static const char ligatures_dst[] =
3019 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
3021 static const struct special
3023 char src;
3024 char dst[4];
3025 } foldczone_special[] =
3027 /* src dst */
3028 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
3029 { 0x98, { 0x20, 0x7e, 0x00 } },
3030 { 0x99, { 0x54, 0x4d, 0x00 } },
3031 { 0xa0, { 0x20, 0x00 } },
3032 { 0xa8, { 0x20, 0xa8, 0x00 } },
3033 { 0xaa, { 0x61, 0x00 } },
3034 { 0xaf, { 0x20, 0xaf, 0x00 } },
3035 { 0xb2, { 0x32, 0x00 } },
3036 { 0xb3, { 0x33, 0x00 } },
3037 { 0xb4, { 0x20, 0xb4, 0x00 } },
3038 { 0xb8, { 0x20, 0xb8, 0x00 } },
3039 { 0xb9, { 0x31, 0x00 } },
3040 { 0xba, { 0x6f, 0x00 } },
3041 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
3042 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
3043 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
3044 { 0x00 }
3047 if (!pFoldStringA)
3048 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3050 /* these tests are locale specific */
3051 if (GetACP() != 1252)
3053 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
3054 return;
3057 /* MAP_FOLDDIGITS */
3058 SetLastError(0);
3059 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
3060 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3062 win_skip("FoldStringA is not implemented\n");
3063 return;
3065 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
3066 ok(strcmp(dst, digits_dst) == 0,
3067 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
3068 for (i = 1; i < 256; i++)
3070 if (!strchr(digits_src, i))
3072 src[0] = i;
3073 src[1] = '\0';
3074 SetLastError(0);
3075 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
3076 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3077 ok(dst[0] == src[0],
3078 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3082 /* MAP_EXPAND_LIGATURES */
3083 SetLastError(0);
3084 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3085 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3086 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3087 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3088 ok(strcmp(dst, ligatures_dst) == 0,
3089 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3090 for (i = 1; i < 256; i++)
3092 if (!strchr(ligatures_src, i))
3094 src[0] = i;
3095 src[1] = '\0';
3096 SetLastError(0);
3097 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3098 if (ret == 3)
3100 /* Vista */
3101 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3102 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3103 "Got %s for %d\n", dst, i);
3105 else
3107 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3108 ok(dst[0] == src[0],
3109 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3115 /* MAP_COMPOSITE */
3116 SetLastError(0);
3117 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3118 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3119 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3120 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3121 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3123 for (i = 1; i < 256; i++)
3125 if (!strchr(composite_src, i))
3127 src[0] = i;
3128 src[1] = '\0';
3129 SetLastError(0);
3130 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3131 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3132 ok(dst[0] == src[0],
3133 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3134 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3138 /* MAP_FOLDCZONE */
3139 for (i = 1; i < 256; i++)
3141 src[0] = i;
3142 src[1] = '\0';
3143 SetLastError(0);
3144 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3145 is_special = FALSE;
3146 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3148 if (foldczone_special[j].src == src[0])
3150 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3151 "Expected ret == 2 or %d, got %d, error %d\n",
3152 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3153 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3154 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3155 (unsigned char)src[0]);
3156 is_special = TRUE;
3159 if (! is_special)
3161 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3162 ok(src[0] == dst[0],
3163 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3164 (unsigned char)src[0], (unsigned char)dst[0]);
3168 /* MAP_PRECOMPOSED */
3169 for (i = 1; i < 256; i++)
3171 src[0] = i;
3172 src[1] = '\0';
3173 SetLastError(0);
3174 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3175 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3176 ok(src[0] == dst[0],
3177 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3178 (unsigned char)src[0], (unsigned char)dst[0]);
3182 static void test_FoldStringW(void)
3184 int ret;
3185 unsigned int i, j;
3186 WCHAR src[256], dst[256], ch, prev_ch = 1;
3187 static const DWORD badFlags[] =
3190 MAP_PRECOMPOSED|MAP_COMPOSITE,
3191 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3192 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3194 /* Ranges of digits 0-9 : Must be sorted! */
3195 static const WCHAR digitRanges[] =
3197 0x0030, /* '0'-'9' */
3198 0x0660, /* Eastern Arabic */
3199 0x06F0, /* Arabic - Hindu */
3200 0x07C0, /* Nko */
3201 0x0966, /* Devengari */
3202 0x09E6, /* Bengalii */
3203 0x0A66, /* Gurmukhi */
3204 0x0AE6, /* Gujarati */
3205 0x0B66, /* Oriya */
3206 0x0BE6, /* Tamil - No 0 */
3207 0x0C66, /* Telugu */
3208 0x0CE6, /* Kannada */
3209 0x0D66, /* Maylayalam */
3210 0x0DE6, /* Sinhala Lith */
3211 0x0E50, /* Thai */
3212 0x0ED0, /* Laos */
3213 0x0F20, /* Tibet */
3214 0x0F29, /* Tibet half - 0 is out of sequence */
3215 0x1040, /* Myanmar */
3216 0x1090, /* Myanmar Shan */
3217 0x1368, /* Ethiopic - no 0 */
3218 0x17E0, /* Khmer */
3219 0x1810, /* Mongolian */
3220 0x1946, /* Limbu */
3221 0x19D0, /* New Tai Lue */
3222 0x1A80, /* Tai Tham Hora */
3223 0x1A90, /* Tai Tham Tham */
3224 0x1B50, /* Balinese */
3225 0x1BB0, /* Sundanese */
3226 0x1C40, /* Lepcha */
3227 0x1C50, /* Ol Chiki */
3228 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3229 0x2080, /* Subscript */
3230 0x245F, /* Circled - 0 is out of sequence */
3231 0x2473, /* Bracketed */
3232 0x2487, /* Full stop */
3233 0x24F4, /* Double Circled */
3234 0x2775, /* Inverted circled - No 0 */
3235 0x277F, /* Patterned circled - No 0 */
3236 0x2789, /* Inverted Patterned circled - No 0 */
3237 0x3020, /* Hangzhou */
3238 0xA620, /* Vai */
3239 0xA8D0, /* Saurashtra */
3240 0xA900, /* Kayah Li */
3241 0xA9D0, /* Javanese */
3242 0xA9F0, /* Myanmar Tai Laing */
3243 0xAA50, /* Cham */
3244 0xABF0, /* Meetei Mayek */
3245 0xff10, /* Pliene chasse (?) */
3246 0xffff /* Terminator */
3248 /* Digits which are represented, but out of sequence */
3249 static const WCHAR outOfSequenceDigits[] =
3251 0xB9, /* Superscript 1 */
3252 0xB2, /* Superscript 2 */
3253 0xB3, /* Superscript 3 */
3254 0x0C78, /* Telugu Fraction 0 */
3255 0x0C79, /* Telugu Fraction 1 */
3256 0x0C7A, /* Telugu Fraction 2 */
3257 0x0C7B, /* Telugu Fraction 3 */
3258 0x0C7C, /* Telugu Fraction 1 */
3259 0x0C7D, /* Telugu Fraction 2 */
3260 0x0C7E, /* Telugu Fraction 3 */
3261 0x0F33, /* Tibetan half zero */
3262 0x19DA, /* New Tai Lue Tham 1 */
3263 0x24EA, /* Circled 0 */
3264 0x24FF, /* Negative Circled 0 */
3265 0x3007, /* Ideographic number zero */
3266 '\0' /* Terminator */
3268 /* Digits in digitRanges for which no representation is available */
3269 static const WCHAR noDigitAvailable[] =
3271 0x0BE6, /* No Tamil 0 */
3272 0x0F29, /* No Tibetan half zero (out of sequence) */
3273 0x1368, /* No Ethiopic 0 */
3274 0x2473, /* No Bracketed 0 */
3275 0x2487, /* No 0 Full stop */
3276 0x24F4, /* No double circled 0 */
3277 0x2775, /* No inverted circled 0 */
3278 0x277F, /* No patterned circled */
3279 0x2789, /* No inverted Patterned circled */
3280 0x3020, /* No Hangzhou 0 */
3281 '\0' /* Terminator */
3283 static const WCHAR foldczone_src[] =
3285 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
3286 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3288 static const WCHAR foldczone_dst[] =
3290 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3292 static const WCHAR foldczone_todo_src[] =
3294 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3296 static const WCHAR foldczone_todo_dst[] =
3298 0x3cb,0x1f0,' ','a',0
3300 static const WCHAR foldczone_todo_broken_dst[] =
3302 0x3cb,0x1f0,0xa0,0xaa,0
3304 static const WCHAR ligatures_src[] =
3306 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
3307 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3308 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3309 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3310 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3311 0xfb04, 0xfb05, 0xfb06, '\0'
3313 static const WCHAR ligatures_dst[] =
3315 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3316 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3317 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3318 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3319 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3320 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3323 if (!pFoldStringW)
3325 win_skip("FoldStringW is not available\n");
3326 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3329 /* Invalid flag combinations */
3330 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3332 src[0] = dst[0] = '\0';
3333 SetLastError(0);
3334 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3335 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3337 win_skip("FoldStringW is not implemented\n");
3338 return;
3340 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3341 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3344 /* src & dst cannot be the same */
3345 SetLastError(0);
3346 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3347 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3348 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3350 /* src can't be NULL */
3351 SetLastError(0);
3352 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3353 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3354 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3356 /* srclen can't be 0 */
3357 SetLastError(0);
3358 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3359 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3360 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3362 /* dstlen can't be < 0 */
3363 SetLastError(0);
3364 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3365 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3366 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3368 /* Ret includes terminating NUL which is appended if srclen = -1 */
3369 SetLastError(0);
3370 src[0] = 'A';
3371 src[1] = '\0';
3372 dst[0] = '\0';
3373 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3374 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3375 ok(dst[0] == 'A' && dst[1] == '\0',
3376 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3377 'A', '\0', ret, dst[0], dst[1], GetLastError());
3379 /* If size is given, result is not NUL terminated */
3380 SetLastError(0);
3381 src[0] = 'A';
3382 src[1] = 'A';
3383 dst[0] = 'X';
3384 dst[1] = 'X';
3385 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3386 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3387 ok(dst[0] == 'A' && dst[1] == 'X',
3388 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3389 'A','X', ret, dst[0], dst[1], GetLastError());
3391 /* MAP_FOLDDIGITS */
3392 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3394 /* Check everything before this range */
3395 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3397 SetLastError(0);
3398 src[0] = ch;
3399 src[1] = dst[0] = '\0';
3400 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3401 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3403 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3404 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3405 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3406 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3407 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3408 "char %04x should not be a digit\n", ch );
3411 if (digitRanges[j] == 0xffff)
3412 break; /* Finished the whole code point space */
3414 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3416 WCHAR c;
3418 /* Map out of sequence characters */
3419 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3420 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3421 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3422 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3423 else c = ch;
3424 SetLastError(0);
3425 src[0] = c;
3426 src[1] = dst[0] = '\0';
3427 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3428 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3430 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3431 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3432 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3433 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3434 strchrW(noDigitAvailable, c),
3435 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3436 ch, '0' + digitRanges[j] - ch, dst[0]);
3438 prev_ch = ch;
3441 /* MAP_FOLDCZONE */
3442 SetLastError(0);
3443 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3444 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3445 "Got %d, error %d\n", ret, GetLastError());
3446 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3447 "MAP_FOLDCZONE: Expanded incorrectly\n");
3449 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3450 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3451 "Got %d, error %d\n", ret, GetLastError());
3452 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3453 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3454 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3456 /* MAP_EXPAND_LIGATURES */
3457 SetLastError(0);
3458 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3459 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3460 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3461 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3462 "Got %d, error %d\n", ret, GetLastError());
3463 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3464 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3467 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3472 #define LCID_OK(l) \
3473 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3474 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3475 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3476 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3477 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3479 static void test_ConvertDefaultLocale(void)
3481 LCID lcid;
3483 /* Doesn't change lcid, even if non default sublang/sort used */
3484 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3485 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3486 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3487 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3489 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3490 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3491 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3492 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3493 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3495 /* Invariant language is not treated specially */
3496 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3498 /* User/system default languages alone are not mapped */
3499 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3500 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3502 /* Default lcids */
3503 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3504 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3505 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3506 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3507 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3508 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3511 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3512 DWORD dwFlags, LONG_PTR lParam)
3514 if (winetest_debug > 1)
3515 trace("%08x, %s, %s, %08x, %08lx\n",
3516 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3518 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3519 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3521 /* If lParam is one, we are calling with flags defaulted from 0 */
3522 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3523 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3525 return TRUE;
3528 static void test_EnumSystemLanguageGroupsA(void)
3530 BOOL ret;
3532 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3534 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3535 return;
3538 /* No enumeration proc */
3539 SetLastError(0);
3540 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3541 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3543 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3544 return;
3546 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3547 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3549 /* Invalid flags */
3550 SetLastError(0);
3551 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3552 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3554 /* No flags - defaults to LGRPID_INSTALLED */
3555 SetLastError(0xdeadbeef);
3556 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3557 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3559 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3560 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3563 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3565 if (winetest_debug > 1)
3566 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3567 return TRUE;
3570 static void test_EnumSystemLocalesEx(void)
3572 BOOL ret;
3574 if (!pEnumSystemLocalesEx)
3576 win_skip( "EnumSystemLocalesEx not available\n" );
3577 return;
3579 SetLastError( 0xdeadbeef );
3580 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3581 ok( !ret, "should have failed\n" );
3582 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3583 SetLastError( 0xdeadbeef );
3584 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3585 ok( ret, "failed err %u\n", GetLastError() );
3588 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3589 LONG_PTR lParam)
3591 if (winetest_debug > 1)
3592 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3594 /* invalid locale enumerated on some platforms */
3595 if (lcid == 0)
3596 return TRUE;
3598 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3599 "Enumerated grp %d not valid\n", lgrpid);
3600 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3601 "Enumerated grp locale %04x not valid\n", lcid);
3602 return TRUE;
3605 static void test_EnumLanguageGroupLocalesA(void)
3607 BOOL ret;
3609 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3611 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3612 return;
3615 /* No enumeration proc */
3616 SetLastError(0);
3617 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3618 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3620 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3621 return;
3623 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3624 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3626 /* lgrpid too small */
3627 SetLastError(0);
3628 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3629 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3630 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3632 /* lgrpid too big */
3633 SetLastError(0);
3634 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3635 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3636 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3638 /* dwFlags is reserved */
3639 SetLastError(0);
3640 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3641 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3642 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3644 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3647 static void test_SetLocaleInfoA(void)
3649 BOOL bRet;
3650 LCID lcid = GetUserDefaultLCID();
3652 /* Null data */
3653 SetLastError(0);
3654 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3655 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3656 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3658 /* IDATE */
3659 SetLastError(0);
3660 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3661 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3662 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3664 /* ILDATE */
3665 SetLastError(0);
3666 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3667 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3668 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3671 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3673 if (winetest_debug > 1)
3674 trace("%s %08lx\n", value, lParam);
3675 return(TRUE);
3678 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3680 ok(!enumCount, "callback called again unexpected\n");
3681 enumCount++;
3682 return(FALSE);
3685 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3687 ok(0,"callback called unexpected\n");
3688 return(FALSE);
3691 static void test_EnumUILanguageA(void)
3693 BOOL ret;
3694 if (!pEnumUILanguagesA) {
3695 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3696 return;
3699 SetLastError(ERROR_SUCCESS);
3700 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3701 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3703 win_skip("EnumUILanguagesA is not implemented\n");
3704 return;
3706 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3708 enumCount = 0;
3709 SetLastError(ERROR_SUCCESS);
3710 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3711 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3713 SetLastError(ERROR_SUCCESS);
3714 ret = pEnumUILanguagesA(NULL, 0, 0);
3715 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3716 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3717 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3719 SetLastError(ERROR_SUCCESS);
3720 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3721 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3722 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3724 SetLastError(ERROR_SUCCESS);
3725 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3726 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3727 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3728 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3731 static char date_fmt_buf[1024];
3732 static WCHAR date_fmt_bufW[1024];
3734 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3736 lstrcatA(date_fmt_buf, fmt);
3737 lstrcatA(date_fmt_buf, "\n");
3738 return TRUE;
3741 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3743 lstrcatW(date_fmt_bufW, fmt);
3744 return FALSE;
3747 static void test_EnumDateFormatsA(void)
3749 char *p, buf[256];
3750 BOOL ret;
3751 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3753 date_fmt_buf[0] = 0;
3754 SetLastError(0xdeadbeef);
3755 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3756 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3758 win_skip("0 for dwFlags is not supported\n");
3760 else
3762 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3763 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3764 /* test the 1st enumerated format */
3765 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3766 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3767 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3768 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3771 date_fmt_buf[0] = 0;
3772 SetLastError(0xdeadbeef);
3773 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3774 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3776 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3778 else
3780 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3781 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3782 /* test the 1st enumerated format */
3783 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3784 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3785 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3786 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3789 date_fmt_buf[0] = 0;
3790 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3791 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3792 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3793 /* test the 1st enumerated format */
3794 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3795 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3796 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3797 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3799 date_fmt_buf[0] = 0;
3800 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3801 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3802 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3803 /* test the 1st enumerated format */
3804 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3805 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3806 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3807 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3809 date_fmt_buf[0] = 0;
3810 SetLastError(0xdeadbeef);
3811 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3812 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3814 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3815 return;
3817 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3818 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3819 /* test the 1st enumerated format */
3820 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3821 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3822 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3823 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3824 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3827 static void test_EnumTimeFormatsA(void)
3829 char *p, buf[256];
3830 BOOL ret;
3831 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3833 date_fmt_buf[0] = 0;
3834 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3835 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3836 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3837 /* test the 1st enumerated format */
3838 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3839 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3840 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3841 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3843 date_fmt_buf[0] = 0;
3844 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3845 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3846 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3847 /* test the 1st enumerated format */
3848 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3849 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3850 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3851 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3854 static void test_EnumTimeFormatsW(void)
3856 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3857 WCHAR bufW[256];
3858 BOOL ret;
3860 date_fmt_bufW[0] = 0;
3861 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3862 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3863 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3864 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3865 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3866 wine_dbgstr_w(bufW));
3868 date_fmt_bufW[0] = 0;
3869 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3870 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3871 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3872 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3873 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3874 wine_dbgstr_w(bufW));
3876 /* TIME_NOSECONDS is Win7+ feature */
3877 date_fmt_bufW[0] = 0;
3878 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3879 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3880 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3881 else {
3882 char buf[256];
3884 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3885 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3886 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3887 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3888 wine_dbgstr_w(bufW));
3890 /* EnumTimeFormatsA doesn't support this flag */
3891 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3892 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3893 GetLastError());
3895 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3896 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3897 GetLastError());
3899 /* And it's not supported by GetLocaleInfoA either */
3900 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3901 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3902 GetLastError());
3905 static void test_GetCPInfo(void)
3907 BOOL ret;
3908 CPINFO cpinfo;
3910 SetLastError(0xdeadbeef);
3911 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3912 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3913 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3914 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3916 SetLastError(0xdeadbeef);
3917 ret = GetCPInfo(CP_UTF7, &cpinfo);
3918 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3920 win_skip("Codepage CP_UTF7 is not installed/available\n");
3922 else
3924 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3925 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3926 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3927 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3928 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3929 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3932 SetLastError(0xdeadbeef);
3933 ret = GetCPInfo(CP_UTF8, &cpinfo);
3934 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3936 win_skip("Codepage CP_UTF8 is not installed/available\n");
3938 else
3940 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3941 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3942 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3943 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3944 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3945 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3946 "expected 4, got %u\n", cpinfo.MaxCharSize);
3951 * The CT_TYPE1 has varied over windows version.
3952 * The current target for correct behavior is windows 7.
3953 * There was a big shift between windows 2000 (first introduced) and windows Xp
3954 * Most of the old values below are from windows 2000.
3955 * A smaller subset of changes happened between windows Xp and Window vista/7
3957 static void test_GetStringTypeW(void)
3959 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3960 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3961 C1_SPACE | C1_BLANK | C1_DEFINED,
3962 C1_SPACE | C1_BLANK | C1_DEFINED,
3963 C1_SPACE | C1_BLANK | C1_DEFINED,
3964 C1_CNTRL | C1_BLANK | C1_DEFINED};
3965 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3966 C1_SPACE | C1_BLANK,
3967 C1_SPACE | C1_BLANK,
3968 C1_SPACE | C1_BLANK,
3969 C1_SPACE | C1_BLANK};
3971 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3973 /* Lu, Ll, Lt */
3974 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3975 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3976 C1_LOWER | C1_ALPHA,
3977 C1_UPPER | C1_LOWER | C1_ALPHA,
3978 C1_ALPHA};
3980 /* Sk, Sk, Mn, So, Me */
3981 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3982 /* Sc, Sm, No,*/
3983 0xffe0, 0xffe9, 0x2153};
3985 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3986 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3987 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3988 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3989 C1_ALPHA | C1_DEFINED,
3990 C1_CNTRL | C1_DEFINED,
3991 C1_PUNCT | C1_DEFINED,
3992 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3993 C1_ALPHA | C1_LOWER | C1_DEFINED,
3994 C1_ALPHA | C1_DEFINED };
3995 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3996 C1_ALPHA | C1_DEFINED,
3997 C1_CNTRL | C1_DEFINED,
3998 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3999 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
4000 C1_ALPHA | C1_DEFINED,
4001 C1_DEFINED
4003 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
4004 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
4006 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
4007 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
4008 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
4009 static const WCHAR lower_special[] = {0x2071, 0x207f};
4010 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
4011 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
4012 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
4013 0xfff9, 0xfffa, 0xfffb};
4014 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
4016 WORD types[20];
4017 WCHAR ch[2];
4018 BOOL ret;
4019 int i;
4021 /* NULL src */
4022 SetLastError(0xdeadbeef);
4023 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
4024 ok(!ret, "got %d\n", ret);
4025 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4027 SetLastError(0xdeadbeef);
4028 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
4029 ok(!ret, "got %d\n", ret);
4030 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4032 SetLastError(0xdeadbeef);
4033 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
4034 ok(!ret, "got %d\n", ret);
4035 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
4037 memset(types,0,sizeof(types));
4038 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
4039 for (i = 0; i < 5; i++)
4040 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]);
4042 memset(types,0,sizeof(types));
4043 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
4044 for (i = 0; i < 3; i++)
4045 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]));
4046 memset(types,0,sizeof(types));
4047 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
4048 for (i = 0; i < 5; i++)
4049 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
4051 memset(types,0,sizeof(types));
4052 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
4053 for (i = 0; i < 8; i++)
4054 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);
4056 memset(types,0,sizeof(types));
4057 GetStringTypeW(CT_CTYPE1, changed, 7, types);
4058 for (i = 0; i < 7; i++)
4059 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]);
4061 memset(types,0,sizeof(types));
4062 GetStringTypeW(CT_CTYPE1, punct, 7, types);
4063 for (i = 0; i < 7; i++)
4064 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));
4067 memset(types,0,sizeof(types));
4068 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
4069 for (i = 0; i < 12; i++)
4070 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);
4072 memset(types,0,sizeof(types));
4073 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
4074 for (i = 0; i < 3; i++)
4075 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);
4077 memset(types,0,sizeof(types));
4078 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
4079 for (i = 0; i < 2; i++)
4080 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);
4082 memset(types,0,sizeof(types));
4083 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4084 for (i = 0; i < 20; i++)
4085 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);
4087 memset(types,0,sizeof(types));
4088 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4089 for (i = 0; i < 3; i++)
4090 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 );
4092 /* surrogate pairs */
4093 ch[0] = 0xd800;
4094 memset(types, 0, sizeof(types));
4095 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4096 if (types[0] == C3_NOTAPPLICABLE)
4097 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4098 else {
4099 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4101 ch[0] = 0xdc00;
4102 memset(types, 0, sizeof(types));
4103 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4104 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4107 /* Zl, Zp categories */
4108 ch[0] = 0x2028;
4109 ch[1] = 0x2029;
4110 memset(types, 0, sizeof(types));
4111 GetStringTypeW(CT_CTYPE1, ch, 2, types);
4112 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4113 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4115 /* check Arabic range for kashida flag */
4116 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4118 types[0] = 0;
4119 ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4120 ok(ret, "%#x: failed %d\n", ch[0], ret);
4121 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4122 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4123 else
4124 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4128 static void test_IdnToNameprepUnicode(void)
4130 struct {
4131 DWORD in_len;
4132 const WCHAR in[64];
4133 DWORD ret;
4134 DWORD broken_ret;
4135 const WCHAR out[64];
4136 DWORD flags;
4137 DWORD err;
4138 DWORD todo;
4139 } test_data[] = {
4141 5, {'t','e','s','t',0},
4142 5, 5, {'t','e','s','t',0},
4143 0, 0xdeadbeef
4146 3, {'a',0xe111,'b'},
4147 0, 0, {0},
4148 0, ERROR_INVALID_NAME
4151 4, {'t',0,'e',0},
4152 0, 0, {0},
4153 0, ERROR_INVALID_NAME
4156 1, {'T',0},
4157 1, 1, {'T',0},
4158 0, 0xdeadbeef
4161 1, {0},
4162 0, 0, {0},
4163 0, ERROR_INVALID_NAME
4166 6, {' ','-','/','[',']',0},
4167 6, 6, {' ','-','/','[',']',0},
4168 0, 0xdeadbeef
4171 3, {'a','-','a'},
4172 3, 3, {'a','-','a'},
4173 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4176 3, {'a','a','-'},
4177 0, 0, {0},
4178 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4180 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4181 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4182 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4183 0, 0xdeadbeef, TRUE
4186 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4187 2, 0, {'t',0},
4188 0, 0xdeadbeef
4190 { /* Another example of incorrectly working FoldString (composition) */
4191 2, {0x3b0, 0},
4192 2, 2, {0x3b0, 0},
4193 0, 0xdeadbeef, TRUE
4196 2, {0x221, 0},
4197 0, 2, {0},
4198 0, ERROR_NO_UNICODE_TRANSLATION
4201 2, {0x221, 0},
4202 2, 2, {0x221, 0},
4203 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4206 5, {'a','.','.','a',0},
4207 0, 0, {0},
4208 0, ERROR_INVALID_NAME
4211 3, {'a','.',0},
4212 3, 3, {'a','.',0},
4213 0, 0xdeadbeef
4217 WCHAR buf[1024];
4218 DWORD i, ret, err;
4220 if (!pIdnToNameprepUnicode)
4222 win_skip("IdnToNameprepUnicode is not available\n");
4223 return;
4226 ret = pIdnToNameprepUnicode(0, test_data[0].in,
4227 test_data[0].in_len, NULL, 0);
4228 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4230 SetLastError(0xdeadbeef);
4231 ret = pIdnToNameprepUnicode(0, test_data[1].in,
4232 test_data[1].in_len, NULL, 0);
4233 err = GetLastError();
4234 ok(ret == test_data[1].ret, "ret = %d\n", ret);
4235 ok(err == test_data[1].err, "err = %d\n", err);
4237 SetLastError(0xdeadbeef);
4238 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
4239 buf, sizeof(buf)/sizeof(WCHAR));
4240 err = GetLastError();
4241 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4242 ok(err == 0xdeadbeef, "err = %d\n", err);
4244 SetLastError(0xdeadbeef);
4245 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
4246 buf, sizeof(buf)/sizeof(WCHAR));
4247 err = GetLastError();
4248 ok(ret == 0, "ret = %d\n", ret);
4249 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4251 SetLastError(0xdeadbeef);
4252 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
4253 buf, sizeof(buf)/sizeof(WCHAR));
4254 err = GetLastError();
4255 ok(ret == 0, "ret = %d\n", ret);
4256 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4258 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4259 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
4260 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4262 SetLastError(0xdeadbeef);
4263 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4264 err = GetLastError();
4265 ok(ret == 0, "ret = %d\n", ret);
4266 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4268 SetLastError(0xdeadbeef);
4269 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4270 err = GetLastError();
4271 ok(ret == 0, "ret = %d\n", ret);
4272 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4273 "err = %d\n", err);
4275 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4277 SetLastError(0xdeadbeef);
4278 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
4279 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
4280 err = GetLastError();
4282 todo_wine_if (test_data[i].todo)
4283 ok(ret == test_data[i].ret ||
4284 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4286 if(ret != test_data[i].ret)
4287 continue;
4289 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4290 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4291 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4295 static void test_IdnToAscii(void)
4297 struct {
4298 DWORD in_len;
4299 const WCHAR in[64];
4300 DWORD ret;
4301 const WCHAR out[64];
4302 DWORD flags;
4303 DWORD err;
4304 } test_data[] = {
4306 5, {'T','e','s','t',0},
4307 5, {'T','e','s','t',0},
4308 0, 0xdeadbeef
4311 5, {'T','e',0x017c,'s','t',0},
4312 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4313 0, 0xdeadbeef
4316 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4317 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4318 0, 0xdeadbeef
4321 3, {0x0105,'.',0},
4322 9, {'x','n','-','-','2','d','a','.',0},
4323 0, 0xdeadbeef
4326 10, {'h','t','t','p',':','/','/','t',0x0106,0},
4327 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4328 0, 0xdeadbeef
4331 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4332 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4333 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4334 0, 0xdeadbeef
4337 2, {0x221,0},
4338 8, {'x','n','-','-','6','l','a',0},
4339 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4343 WCHAR buf[1024];
4344 DWORD i, ret, err;
4346 if (!pIdnToAscii)
4348 win_skip("IdnToAscii is not available\n");
4349 return;
4352 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4354 SetLastError(0xdeadbeef);
4355 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4356 test_data[i].in_len, buf, sizeof(buf));
4357 err = GetLastError();
4358 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4359 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4360 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4361 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4365 static void test_IdnToUnicode(void)
4367 struct {
4368 DWORD in_len;
4369 const WCHAR in[64];
4370 DWORD ret;
4371 const WCHAR out[64];
4372 DWORD flags;
4373 DWORD err;
4374 } test_data[] = {
4376 5, {'T','e','s','.',0},
4377 5, {'T','e','s','.',0},
4378 0, 0xdeadbeef
4381 2, {0x105,0},
4382 0, {0},
4383 0, ERROR_INVALID_NAME
4386 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4387 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4388 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4389 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4390 0x05d1,0x05e8,0x05d9,0x05ea,0},
4391 0, 0xdeadbeef
4394 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4395 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4396 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4397 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4398 0, 0xdeadbeef
4401 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4402 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4403 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4404 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4405 0, {0},
4406 0, ERROR_INVALID_NAME
4409 8, {'x','n','-','-','6','l','a',0},
4410 2, {0x221,0},
4411 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4415 WCHAR buf[1024];
4416 DWORD i, ret, err;
4418 if (!pIdnToUnicode)
4420 win_skip("IdnToUnicode is not available\n");
4421 return;
4424 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4426 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4427 test_data[i].in_len, NULL, 0);
4428 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4430 SetLastError(0xdeadbeef);
4431 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4432 test_data[i].in_len, buf, sizeof(buf));
4433 err = GetLastError();
4434 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4435 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4436 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4437 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4441 static void test_GetLocaleInfoEx(void)
4443 static const WCHAR enW[] = {'e','n',0};
4444 WCHAR bufferW[80], buffer2[80];
4445 INT ret;
4447 if (!pGetLocaleInfoEx)
4449 win_skip("GetLocaleInfoEx not supported\n");
4450 return;
4453 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4454 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4455 if (ret)
4457 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4458 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4459 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4460 static const WCHAR usaW[] = {'U','S','A',0};
4461 static const WCHAR enuW[] = {'E','N','U',0};
4462 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4463 DWORD val;
4465 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4466 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4468 SetLastError(0xdeadbeef);
4469 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4470 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4472 SetLastError(0xdeadbeef);
4473 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4474 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4476 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4477 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4478 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4480 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4481 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4482 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4484 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4485 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4486 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4488 ret = pGetLocaleInfoEx(enusW, LOCALE_SPARENT, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4489 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4490 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4492 ret = pGetLocaleInfoEx(enW, LOCALE_SPARENT, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4493 ok(ret == 1, "got %d\n", ret);
4494 ok(!bufferW[0], "got %s\n", wine_dbgstr_w(bufferW));
4496 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4497 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4498 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4499 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4501 skip("Non-English locale\n");
4503 else
4504 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4506 bufferW[0] = 0;
4507 SetLastError(0xdeadbeef);
4508 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4509 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4511 while (*ptr->name)
4513 val = 0;
4514 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4515 todo_wine_if (ptr->todo)
4516 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4517 bufferW[0] = 0;
4518 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4519 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4520 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4521 ptr++;
4524 ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4525 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4526 ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR));
4527 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4528 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4532 static void test_IsValidLocaleName(void)
4534 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4535 static const WCHAR zzW[] = {'z','z',0};
4536 static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0};
4537 static const WCHAR zzzzW[] = {'z','z','z','z',0};
4538 BOOL ret;
4540 if (!pIsValidLocaleName)
4542 win_skip("IsValidLocaleName not supported\n");
4543 return;
4546 ret = pIsValidLocaleName(enusW);
4547 ok(ret, "IsValidLocaleName failed\n");
4548 ret = pIsValidLocaleName(zzW);
4549 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4550 ret = pIsValidLocaleName(zz_zzW);
4551 ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
4552 ret = pIsValidLocaleName(zzzzW);
4553 ok(!ret, "IsValidLocaleName should have failed\n");
4554 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4555 ok(ret, "IsValidLocaleName failed\n");
4556 ret = pIsValidLocaleName(NULL);
4557 ok(!ret, "IsValidLocaleName should have failed\n");
4560 static void test_CompareStringOrdinal(void)
4562 INT ret;
4563 WCHAR test1[] = { 't','e','s','t',0 };
4564 WCHAR test2[] = { 'T','e','S','t',0 };
4565 WCHAR test3[] = { 't','e','s','t','3',0 };
4566 WCHAR null1[] = { 'a',0,'a',0 };
4567 WCHAR null2[] = { 'a',0,'b',0 };
4568 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4569 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4570 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4571 WCHAR coop2[] = { 'c','o','o','p',0 };
4572 WCHAR nonascii1[] = { 0x0102,0 };
4573 WCHAR nonascii2[] = { 0x0201,0 };
4574 WCHAR ch1, ch2;
4576 if (!pCompareStringOrdinal)
4578 win_skip("CompareStringOrdinal not supported\n");
4579 return;
4582 /* Check errors */
4583 SetLastError(0xdeadbeef);
4584 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4585 ok(!ret, "Got %u, expected 0\n", ret);
4586 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4587 SetLastError(0xdeadbeef);
4588 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4589 ok(!ret, "Got %u, expected 0\n", ret);
4590 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4591 SetLastError(0xdeadbeef);
4592 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4593 ok(!ret, "Got %u, expected 0\n", ret);
4594 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4596 /* Check case */
4597 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4598 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4599 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4600 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4601 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4602 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4603 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4604 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4606 /* Check different sizes */
4607 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4608 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4609 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4610 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4612 /* Check null character */
4613 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4614 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4615 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4616 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4617 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4618 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4619 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4620 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4622 /* Check ordinal behaviour */
4623 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4624 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4625 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4626 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4627 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4628 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4629 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4630 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4632 for (ch1 = 0; ch1 < 512; ch1++)
4634 for (ch2 = 0; ch2 < 1024; ch2++)
4636 int diff = ch1 - ch2;
4637 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4638 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4639 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4640 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4641 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4642 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4643 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4648 static void test_GetGeoInfo(void)
4650 char buffA[20];
4651 INT ret;
4653 if (!pGetGeoInfoA)
4655 win_skip("GetGeoInfo is not available.\n");
4656 return;
4659 /* unassigned id */
4660 SetLastError(0xdeadbeef);
4661 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4662 ok(ret == 0, "got %d\n", ret);
4663 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4665 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4666 ok(ret == 3, "got %d\n", ret);
4668 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4669 ok(ret == 4, "got %d\n", ret);
4671 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4672 ok(ret == 3, "got %d\n", ret);
4673 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4675 /* buffer pointer not NULL, length is 0 - return required length */
4676 buffA[0] = 'a';
4677 SetLastError(0xdeadbeef);
4678 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4679 ok(ret == 3, "got %d\n", ret);
4680 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4682 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4683 ok(ret == 4, "got %d\n", ret);
4684 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4686 /* shorter buffer */
4687 SetLastError(0xdeadbeef);
4688 buffA[1] = buffA[2] = 0;
4689 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4690 ok(ret == 0, "got %d\n", ret);
4691 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4692 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4694 /* GEO_NATION returns GEOID in a string form */
4695 buffA[0] = 0;
4696 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4697 ok(ret == 4, "got %d\n", ret);
4698 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4700 /* GEO_PARENT */
4701 buffA[0] = 0;
4702 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4703 if (ret == 0)
4704 win_skip("GEO_PARENT not supported.\n");
4705 else
4707 ok(ret == 6, "got %d\n", ret);
4708 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4711 buffA[0] = 0;
4712 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4713 if (ret == 0)
4714 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4715 else
4717 ok(ret == 4, "got %d\n", ret);
4718 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4721 /* try invalid type value */
4722 SetLastError(0xdeadbeef);
4723 ret = pGetGeoInfoA(203, GEO_ID + 1, NULL, 0, 0);
4724 ok(ret == 0, "got %d\n", ret);
4725 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4728 static int geoidenum_count;
4729 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4731 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4732 ok(ret == 3, "got %d for %d\n", ret, geoid);
4733 /* valid geoid starts at 2 */
4734 ok(geoid >= 2, "got geoid %d\n", geoid);
4736 return geoidenum_count++ < 5;
4739 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4741 geoidenum_count++;
4742 return TRUE;
4745 static void test_EnumSystemGeoID(void)
4747 BOOL ret;
4749 if (!pEnumSystemGeoID)
4751 win_skip("EnumSystemGeoID is not available.\n");
4752 return;
4755 SetLastError(0xdeadbeef);
4756 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4757 ok(!ret, "got %d\n", ret);
4758 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4760 SetLastError(0xdeadbeef);
4761 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4762 ok(!ret, "got %d\n", ret);
4763 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4765 SetLastError(0xdeadbeef);
4766 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4767 ok(!ret, "got %d\n", ret);
4768 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4770 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4771 ok(ret, "got %d\n", ret);
4773 /* only the first level is enumerated, not the whole hierarchy */
4774 geoidenum_count = 0;
4775 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4776 if (ret == 0)
4777 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4778 else
4779 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4781 geoidenum_count = 0;
4782 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4783 if (ret == 0)
4784 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4785 else
4787 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4789 geoidenum_count = 0;
4790 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4791 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4795 struct invariant_entry {
4796 const char *name;
4797 int id;
4798 const char *expect, *expect2;
4801 #define X(x) #x, x
4802 static const struct invariant_entry invariant_list[] = {
4803 { X(LOCALE_ILANGUAGE), "007f" },
4804 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4805 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4806 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4807 { X(LOCALE_ICOUNTRY), "1" },
4808 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4809 { X(LOCALE_SABBREVCTRYNAME), "IVC", "" },
4810 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4811 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4812 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4813 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4814 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4815 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4816 { X(LOCALE_SLIST), "," },
4817 { X(LOCALE_IMEASURE), "0" },
4818 { X(LOCALE_SDECIMAL), "." },
4819 { X(LOCALE_STHOUSAND), "," },
4820 { X(LOCALE_SGROUPING), "3;0" },
4821 { X(LOCALE_IDIGITS), "2" },
4822 { X(LOCALE_ILZERO), "1" },
4823 { X(LOCALE_INEGNUMBER), "1" },
4824 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4825 { X(LOCALE_SCURRENCY), "\x00a4" },
4826 { X(LOCALE_SINTLSYMBOL), "XDR" },
4827 { X(LOCALE_SMONDECIMALSEP), "." },
4828 { X(LOCALE_SMONTHOUSANDSEP), "," },
4829 { X(LOCALE_SMONGROUPING), "3;0" },
4830 { X(LOCALE_ICURRDIGITS), "2" },
4831 { X(LOCALE_IINTLCURRDIGITS), "2" },
4832 { X(LOCALE_ICURRENCY), "0" },
4833 { X(LOCALE_INEGCURR), "0" },
4834 { X(LOCALE_SDATE), "/" },
4835 { X(LOCALE_STIME), ":" },
4836 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4837 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4838 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4839 { X(LOCALE_IDATE), "0" },
4840 { X(LOCALE_ILDATE), "1" },
4841 { X(LOCALE_ITIME), "1" },
4842 { X(LOCALE_ITIMEMARKPOSN), "0" },
4843 { X(LOCALE_ICENTURY), "1" },
4844 { X(LOCALE_ITLZERO), "1" },
4845 { X(LOCALE_IDAYLZERO), "1" },
4846 { X(LOCALE_IMONLZERO), "1" },
4847 { X(LOCALE_S1159), "AM" },
4848 { X(LOCALE_S2359), "PM" },
4849 { X(LOCALE_ICALENDARTYPE), "1" },
4850 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4851 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4852 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4853 { X(LOCALE_SDAYNAME1), "Monday" },
4854 { X(LOCALE_SDAYNAME2), "Tuesday" },
4855 { X(LOCALE_SDAYNAME3), "Wednesday" },
4856 { X(LOCALE_SDAYNAME4), "Thursday" },
4857 { X(LOCALE_SDAYNAME5), "Friday" },
4858 { X(LOCALE_SDAYNAME6), "Saturday" },
4859 { X(LOCALE_SDAYNAME7), "Sunday" },
4860 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4861 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4862 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4863 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4864 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4865 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4866 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4867 { X(LOCALE_SMONTHNAME1), "January" },
4868 { X(LOCALE_SMONTHNAME2), "February" },
4869 { X(LOCALE_SMONTHNAME3), "March" },
4870 { X(LOCALE_SMONTHNAME4), "April" },
4871 { X(LOCALE_SMONTHNAME5), "May" },
4872 { X(LOCALE_SMONTHNAME6), "June" },
4873 { X(LOCALE_SMONTHNAME7), "July" },
4874 { X(LOCALE_SMONTHNAME8), "August" },
4875 { X(LOCALE_SMONTHNAME9), "September" },
4876 { X(LOCALE_SMONTHNAME10), "October" },
4877 { X(LOCALE_SMONTHNAME11), "November" },
4878 { X(LOCALE_SMONTHNAME12), "December" },
4879 { X(LOCALE_SMONTHNAME13), "" },
4880 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4881 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4882 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4883 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4884 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4885 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4886 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4887 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4888 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4889 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4890 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4891 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4892 { X(LOCALE_SABBREVMONTHNAME13), "" },
4893 { X(LOCALE_SPOSITIVESIGN), "+" },
4894 { X(LOCALE_SNEGATIVESIGN), "-" },
4895 { X(LOCALE_IPOSSIGNPOSN), "3" },
4896 { X(LOCALE_INEGSIGNPOSN), "0" },
4897 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4898 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4899 { X(LOCALE_INEGSYMPRECEDES), "1" },
4900 { X(LOCALE_INEGSEPBYSPACE), "0" },
4901 { X(LOCALE_SISO639LANGNAME), "iv" },
4902 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4903 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4904 { X(LOCALE_IPAPERSIZE), "9" },
4905 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4906 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4907 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4908 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4909 { X(LOCALE_SNAME), "" },
4910 { X(LOCALE_SSCRIPTS), "Latn;" },
4911 { 0 }
4913 #undef X
4915 static void test_invariant(void)
4917 int ret;
4918 int len;
4919 char buffer[BUFFER_SIZE];
4920 const struct invariant_entry *ptr = invariant_list;
4922 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4924 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4925 return;
4928 while (ptr->name)
4930 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4931 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4932 win_skip("not supported\n"); /* winxp/win2k3 */
4933 else
4935 len = strlen(ptr->expect)+1; /* include \0 */
4936 ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
4937 "For id %d, expected ret == %d, got %d, error %d\n",
4938 ptr->id, len, ret, GetLastError());
4939 ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
4940 "For id %d, Expected %s, got '%s'\n",
4941 ptr->id, ptr->expect, buffer);
4944 ptr++;
4947 if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) ||
4948 (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
4950 skip("Non US-English locale\n");
4952 else
4954 /* some locales translate these */
4955 static const char lang[] = "Invariant Language (Invariant Country)";
4956 static const char cntry[] = "Invariant Country";
4957 static const char sortm[] = "Math Alphanumerics";
4958 static const char sortd[] = "Default"; /* win2k3 */
4960 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4961 len = lstrlenA(lang) + 1;
4962 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4963 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4965 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4966 len = lstrlenA(cntry) + 1;
4967 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4968 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4970 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4971 if (ret == lstrlenA(sortm)+1)
4972 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4973 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4974 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4975 else
4976 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4977 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4981 static void test_GetSystemPreferredUILanguages(void)
4983 BOOL ret;
4984 ULONG count, size, size_id, size_name, size_buffer;
4985 WCHAR *buffer;
4988 if (!pGetSystemPreferredUILanguages)
4990 win_skip("GetSystemPreferredUILanguages is not available.\n");
4991 return;
4994 /* (in)valid first parameter */
4995 count = 0xdeadbeef;
4996 size = 0;
4997 SetLastError(0xdeadbeef);
4998 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4999 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5000 ok(count, "Expected count > 0\n");
5001 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5003 count = 0xdeadbeef;
5004 size = 0;
5005 SetLastError(0xdeadbeef);
5006 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5007 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5008 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5009 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5011 count = 0xdeadbeef;
5012 size = 0;
5013 SetLastError(0xdeadbeef);
5014 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5015 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5016 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5017 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5019 count = 0xdeadbeef;
5020 size = 0;
5021 SetLastError(0xdeadbeef);
5022 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
5023 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5024 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5025 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5027 count = 0xdeadbeef;
5028 size = 0;
5029 SetLastError(0xdeadbeef);
5030 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5031 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5032 ok(count, "Expected count > 0\n");
5033 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5035 count = 0xdeadbeef;
5036 size = 0;
5037 SetLastError(0xdeadbeef);
5038 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5039 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5040 ok(count, "Expected count > 0\n");
5041 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5043 /* second parameter
5044 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
5045 * -> unhandled exception c0000005
5048 /* invalid third parameter */
5049 count = 0xdeadbeef;
5050 size = 1;
5051 SetLastError(0xdeadbeef);
5052 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5053 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5054 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5055 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5057 /* fourth parameter
5058 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
5059 * -> unhandled exception c0000005
5062 count = 0xdeadbeef;
5063 size_id = 0;
5064 SetLastError(0xdeadbeef);
5065 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5066 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5067 ok(count, "Expected count > 0\n");
5068 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5070 count = 0xdeadbeef;
5071 size_name = 0;
5072 SetLastError(0xdeadbeef);
5073 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5074 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5075 ok(count, "Expected count > 0\n");
5076 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5078 size_buffer = max(size_id, size_name);
5079 if(!size_buffer)
5081 skip("No valid buffer size\n");
5082 return;
5085 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5086 if (!buffer)
5088 skip("Failed to allocate memory for %d chars\n", size_buffer);
5089 return;
5092 count = 0xdeadbeef;
5093 size = size_buffer;
5094 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5095 SetLastError(0xdeadbeef);
5096 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5097 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5098 ok(count, "Expected count > 0\n");
5099 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5100 if (ret && size % 6 == 1)
5101 ok(!buffer[size -2] && !buffer[size -1],
5102 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5103 buffer[size -2], buffer[size -1]);
5105 count = 0xdeadbeef;
5106 size = size_buffer;
5107 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5108 SetLastError(0xdeadbeef);
5109 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5110 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5111 ok(count, "Expected count > 0\n");
5112 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5113 if (ret && size % 5 == 1)
5114 ok(!buffer[size -2] && !buffer[size -1],
5115 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5116 buffer[size -2], buffer[size -1]);
5118 count = 0xdeadbeef;
5119 size = size_buffer;
5120 SetLastError(0xdeadbeef);
5121 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5122 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5123 ok(count, "Expected count > 0\n");
5124 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5125 if (ret && size % 5 == 1)
5126 ok(!buffer[size -2] && !buffer[size -1],
5127 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5128 buffer[size -2], buffer[size -1]);
5130 count = 0xdeadbeef;
5131 size = 0;
5132 SetLastError(0xdeadbeef);
5133 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5134 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5135 ok(count, "Expected count > 0\n");
5136 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5137 if (ret && size % 6 == 1)
5138 ok(!buffer[size -2] && !buffer[size -1],
5139 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5140 buffer[size -2], buffer[size -1]);
5142 count = 0xdeadbeef;
5143 size = 1;
5144 SetLastError(0xdeadbeef);
5145 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5146 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5147 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5148 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5150 count = 0xdeadbeef;
5151 size = size_id -1;
5152 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5153 SetLastError(0xdeadbeef);
5154 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5155 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5156 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5157 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5159 count = 0xdeadbeef;
5160 size = size_id -2;
5161 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5162 SetLastError(0xdeadbeef);
5163 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5164 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5165 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5166 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5168 HeapFree(GetProcessHeap(), 0, buffer);
5171 static void test_GetThreadPreferredUILanguages(void)
5173 BOOL ret;
5174 ULONG count, size;
5175 WCHAR *buf;
5177 if (!pGetThreadPreferredUILanguages)
5179 win_skip("GetThreadPreferredUILanguages is not available.\n");
5180 return;
5183 size = count = 0;
5184 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5185 ok(ret, "got %u\n", GetLastError());
5186 ok(count, "expected count > 0\n");
5187 ok(size, "expected size > 0\n");
5189 count = 0;
5190 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5191 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5192 ok(ret, "got %u\n", GetLastError());
5193 ok(count, "expected count > 0\n");
5194 HeapFree(GetProcessHeap(), 0, buf);
5197 static void test_GetUserPreferredUILanguages(void)
5199 BOOL ret;
5200 ULONG count, size, size_id, size_name, size_buffer;
5201 WCHAR *buffer;
5204 if (!pGetUserPreferredUILanguages)
5206 win_skip("GetUserPreferredUILanguages is not available.\n");
5207 return;
5210 count = 0xdeadbeef;
5211 size = 0;
5212 SetLastError(0xdeadbeef);
5213 ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
5214 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5215 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5216 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5218 count = 0xdeadbeef;
5219 size = 0;
5220 SetLastError(0xdeadbeef);
5221 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
5222 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5223 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5224 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5226 count = 0xdeadbeef;
5227 size = 0;
5228 SetLastError(0xdeadbeef);
5229 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5230 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5231 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5232 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5234 count = 0xdeadbeef;
5235 size = 1;
5236 SetLastError(0xdeadbeef);
5237 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
5238 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5239 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5240 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
5242 count = 0xdeadbeef;
5243 size_id = 0;
5244 SetLastError(0xdeadbeef);
5245 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
5246 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5247 ok(count, "Expected count > 0\n");
5248 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
5250 count = 0xdeadbeef;
5251 size_name = 0;
5252 SetLastError(0xdeadbeef);
5253 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
5254 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5255 ok(count, "Expected count > 0\n");
5256 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
5258 size_buffer = max(size_id, size_name);
5259 if(!size_buffer)
5261 skip("No valid buffer size\n");
5262 return;
5265 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
5267 count = 0xdeadbeef;
5268 size = size_buffer;
5269 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5270 SetLastError(0xdeadbeef);
5271 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5272 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5273 ok(count, "Expected count > 0\n");
5274 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5275 if (ret && size % 6 == 1)
5276 ok(!buffer[size -2] && !buffer[size -1],
5277 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5278 buffer[size -2], buffer[size -1]);
5280 count = 0xdeadbeef;
5281 size = size_buffer;
5282 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5283 SetLastError(0xdeadbeef);
5284 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5285 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5286 ok(count, "Expected count > 0\n");
5287 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5288 if (ret && size % 5 == 1)
5289 ok(!buffer[size -2] && !buffer[size -1],
5290 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5291 buffer[size -2], buffer[size -1]);
5293 count = 0xdeadbeef;
5294 size = size_buffer;
5295 SetLastError(0xdeadbeef);
5296 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5297 ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
5298 ok(count, "Expected count > 0\n");
5299 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5300 if (ret && size % 5 == 1)
5301 ok(!buffer[size -2] && !buffer[size -1],
5302 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5303 buffer[size -2], buffer[size -1]);
5305 count = 0xdeadbeef;
5306 size = 1;
5307 SetLastError(0xdeadbeef);
5308 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5309 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5310 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5311 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5313 count = 0xdeadbeef;
5314 size = size_id -1;
5315 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5316 SetLastError(0xdeadbeef);
5317 ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5318 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5319 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5320 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5322 count = 0xdeadbeef;
5323 size = size_id -2;
5324 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5325 SetLastError(0xdeadbeef);
5326 ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
5327 ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
5328 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5329 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5331 HeapFree(GetProcessHeap(), 0, buffer);
5334 static void test_FindNLSStringEx(void)
5336 INT res;
5337 static WCHAR en_simpsimpW[] = {'S','i','m','p','l','e','S','i','m','p','l','e',0};
5338 static WCHAR en_simpW[] = {'S','i','m','p','l','e',0};
5339 static WCHAR comb_s_accent1W[] = {0x1e69, 'o','u','r','c','e',0};
5340 static WCHAR comb_s_accent2W[] = {0x0073,0x323,0x307,'o','u','r','c','e',0};
5341 static WCHAR comb_q_accent1W[] = {0x0071,0x0307,0x323,'u','o','t','e',0};
5342 static WCHAR comb_q_accent2W[] = {0x0071,0x0323,0x307,'u','o','t','e',0};
5343 struct test_data {
5344 const WCHAR *locale;
5345 DWORD flags;
5346 WCHAR *src;
5347 INT src_size;
5348 WCHAR *value;
5349 INT val_size;
5350 INT found;
5351 INT expected_ret;
5352 INT expected_found;
5353 int todo;
5354 BOOL broken_vista_servers;
5357 static struct test_data test_arr[] =
5359 { localeW, FIND_FROMSTART, en_simpsimpW, sizeof(en_simpsimpW)/sizeof(WCHAR)-1,
5360 en_simpW, sizeof(en_simpW)/sizeof(WCHAR)-1, 0, 0, 6, 0, FALSE},
5361 { localeW, FIND_FROMEND, en_simpsimpW, sizeof(en_simpsimpW)/sizeof(WCHAR)-1,
5362 en_simpW, sizeof(en_simpW)/sizeof(WCHAR)-1, 0, 6, 6, 0, FALSE},
5363 { localeW, FIND_STARTSWITH, en_simpsimpW, sizeof(en_simpsimpW)/sizeof(WCHAR)-1,
5364 en_simpW, sizeof(en_simpW)/sizeof(WCHAR)-1, 0, 0, 6, 0, FALSE},
5365 { localeW, FIND_ENDSWITH, en_simpsimpW, sizeof(en_simpsimpW)/sizeof(WCHAR)-1,
5366 en_simpW, sizeof(en_simpW)/sizeof(WCHAR)-1, 0, 6, 6, 0, FALSE},
5367 { localeW, FIND_FROMSTART, comb_s_accent1W, sizeof(comb_s_accent1W)/sizeof(WCHAR)-1,
5368 comb_s_accent2W, sizeof(comb_s_accent2W)/sizeof(WCHAR)-1, 0, 0, 6, 1, TRUE },
5369 { localeW, FIND_FROMSTART, comb_q_accent1W, sizeof(comb_q_accent1W)/sizeof(WCHAR)-1,
5370 comb_q_accent2W, sizeof(comb_q_accent2W)/sizeof(WCHAR)-1, 0, 0, 7, 1, FALSE },
5371 { 0 }
5373 struct test_data *ptest;
5375 if (!pFindNLSStringEx)
5377 win_skip("FindNLSStringEx is not available.\n");
5378 return;
5381 SetLastError( 0xdeadbeef );
5382 res = pFindNLSStringEx(invalidW, FIND_FROMSTART, fooW, 3, fooW,
5383 3, NULL, NULL, NULL, 0);
5384 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5385 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5386 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5388 SetLastError( 0xdeadbeef );
5389 res = pFindNLSStringEx(localeW, FIND_FROMSTART, NULL, 3, fooW, 3,
5390 NULL, NULL, NULL, 0);
5391 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5392 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5393 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5395 SetLastError( 0xdeadbeef );
5396 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, -5, fooW, 3,
5397 NULL, NULL, NULL, 0);
5398 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5399 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5400 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5402 SetLastError( 0xdeadbeef );
5403 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, NULL, 3,
5404 NULL, NULL, NULL, 0);
5405 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5406 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5407 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5409 SetLastError( 0xdeadbeef );
5410 res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, fooW, -5,
5411 NULL, NULL, NULL, 0);
5412 ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res);
5413 ok(ERROR_INVALID_PARAMETER == GetLastError(),
5414 "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError());
5416 for (ptest = test_arr; ptest->src != NULL; ptest++)
5418 todo_wine_if(ptest->todo)
5420 res = pFindNLSStringEx(ptest->locale, ptest->flags, ptest->src, ptest->src_size,
5421 ptest->value, ptest->val_size, &ptest->found, NULL, NULL, 0);
5422 if (ptest->broken_vista_servers)
5424 ok(res == ptest->expected_ret || /* Win 7 onwards */
5425 broken(res == -1), /* Win Vista, Server 2003 and 2008 */
5426 "Expected FindNLSStringEx to return %d. Returned value was %d\n",
5427 ptest->expected_ret, res);
5428 ok(ptest->found == ptest->expected_found || /* Win 7 onwards */
5429 broken(ptest->found == 0), /* Win Vista, Server 2003 and 2008 */
5430 "Expected FindNLSStringEx to output %d. Value was %d\n",
5431 ptest->expected_found, ptest->found);
5433 else
5435 ok(res == ptest->expected_ret,
5436 "Expected FindNLSStringEx to return %d. Returned value was %d\n",
5437 ptest->expected_ret, res);
5438 ok(ptest->found == ptest->expected_found,
5439 "Expected FindNLSStringEx to output %d. Value was %d\n",
5440 ptest->expected_found, ptest->found);
5446 START_TEST(locale)
5448 InitFunctionPointers();
5450 test_EnumTimeFormatsA();
5451 test_EnumTimeFormatsW();
5452 test_EnumDateFormatsA();
5453 test_GetLocaleInfoA();
5454 test_GetLocaleInfoW();
5455 test_GetLocaleInfoEx();
5456 test_GetTimeFormatA();
5457 test_GetTimeFormatEx();
5458 test_GetDateFormatA();
5459 test_GetDateFormatEx();
5460 test_GetDateFormatW();
5461 test_GetCurrencyFormatA(); /* Also tests the W version */
5462 test_GetNumberFormatA(); /* Also tests the W version */
5463 test_GetNumberFormatEx();
5464 test_CompareStringA();
5465 test_CompareStringW();
5466 test_CompareStringEx();
5467 test_LCMapStringA();
5468 test_LCMapStringW();
5469 test_LCMapStringEx();
5470 test_LocaleNameToLCID();
5471 test_FoldStringA();
5472 test_FoldStringW();
5473 test_ConvertDefaultLocale();
5474 test_EnumSystemLanguageGroupsA();
5475 test_EnumSystemLocalesEx();
5476 test_EnumLanguageGroupLocalesA();
5477 test_SetLocaleInfoA();
5478 test_EnumUILanguageA();
5479 test_GetCPInfo();
5480 test_GetStringTypeW();
5481 test_IdnToNameprepUnicode();
5482 test_IdnToAscii();
5483 test_IdnToUnicode();
5484 test_IsValidLocaleName();
5485 test_CompareStringOrdinal();
5486 test_GetGeoInfo();
5487 test_EnumSystemGeoID();
5488 test_invariant();
5489 test_GetSystemPreferredUILanguages();
5490 test_GetThreadPreferredUILanguages();
5491 test_GetUserPreferredUILanguages();
5492 test_FindNLSStringEx();
5493 /* this requires collation table patch to make it MS compatible */
5494 if (0) test_sorting();