kernel32/tests: Add more mapping tests for LCMapString.
[wine.git] / dlls / kernel32 / tests / locale.c
blob5e149d8867c0640392ab9e8c19adfb1067d7d160
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};
47 static inline unsigned int strlenW( const WCHAR *str )
49 const WCHAR *s = str;
50 while (*s) s++;
51 return s - str;
54 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
56 if (n <= 0) return 0;
57 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
58 return *str1 - *str2;
61 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
63 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
64 return NULL;
67 static inline BOOL isdigitW( WCHAR wc )
69 WORD type;
70 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
71 return type & C1_DIGIT;
74 /* Some functions are only in later versions of kernel32.dll */
75 static WORD enumCount;
77 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
78 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
79 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
80 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
83 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
84 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
85 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
86 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
87 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
88 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
89 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
90 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
93 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
94 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
95 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
96 LPNLSVERSIONINFO, LPVOID, LPARAM);
97 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
98 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
99 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
100 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
101 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
103 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
105 static void InitFunctionPointers(void)
107 HMODULE mod = GetModuleHandleA("kernel32");
109 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
110 X(GetTimeFormatEx);
111 X(GetDateFormatEx);
112 X(EnumSystemLanguageGroupsA);
113 X(EnumLanguageGroupLocalesA);
114 X(LocaleNameToLCID);
115 X(LCIDToLocaleName);
116 X(LCMapStringEx);
117 X(FoldStringA);
118 X(FoldStringW);
119 X(IsValidLanguageGroup);
120 X(EnumUILanguagesA);
121 X(EnumSystemLocalesEx);
122 X(IdnToNameprepUnicode);
123 X(IdnToAscii);
124 X(IdnToUnicode);
125 X(GetLocaleInfoEx);
126 X(IsValidLocaleName);
127 X(CompareStringOrdinal);
128 X(CompareStringEx);
129 X(GetGeoInfoA);
130 X(GetGeoInfoW);
131 X(EnumSystemGeoID);
132 X(GetSystemPreferredUILanguages);
133 X(GetThreadPreferredUILanguages);
134 X(GetNumberFormatEx);
136 mod = GetModuleHandleA("ntdll");
137 X(RtlUpcaseUnicodeChar);
138 #undef X
141 #define eq(received, expected, label, type) \
142 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
143 (label), (received), (expected))
145 #define BUFFER_SIZE 128
146 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
148 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
149 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
150 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
151 "Expected '%s', got '%s'\n", Expected, buffer)
153 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
154 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
155 SetLastError(0xdeadbeef); buffer[0] = '\0'
156 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
157 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
159 #define NUO LOCALE_NOUSEROVERRIDE
161 static void test_GetLocaleInfoA(void)
163 int ret;
164 int len;
165 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
166 char buffer[BUFFER_SIZE];
167 char expected[BUFFER_SIZE];
168 DWORD val;
170 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
172 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
173 ok(ret, "got %d\n", ret);
174 ok(val == lcid, "got 0x%08x\n", val);
176 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
177 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
178 assumes SUBLANG_NEUTRAL for zh */
179 memset(expected, 0, COUNTOF(expected));
180 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
181 SetLastError(0xdeadbeef);
182 memset(buffer, 0, COUNTOF(buffer));
183 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
184 ok((ret == len) && !lstrcmpA(buffer, expected),
185 "got %d with '%s' (expected %d with '%s')\n",
186 ret, buffer, len, expected);
188 memset(expected, 0, COUNTOF(expected));
189 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
190 if (len) {
191 SetLastError(0xdeadbeef);
192 memset(buffer, 0, COUNTOF(buffer));
193 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
194 ok((ret == len) && !lstrcmpA(buffer, expected),
195 "got %d with '%s' (expected %d with '%s')\n",
196 ret, buffer, len, expected);
198 else
199 win_skip("LANG_ARABIC not installed\n");
201 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
202 memset(expected, 0, COUNTOF(expected));
203 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
204 SetLastError(0xdeadbeef);
205 memset(buffer, 0, COUNTOF(buffer));
206 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
207 ok((ret == len) && !lstrcmpA(buffer, expected),
208 "got %d with '%s' (expected %d with '%s')\n",
209 ret, buffer, len, expected);
212 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
213 * partially fill the buffer even if it is too short. See bug 637.
215 SetLastError(0xdeadbeef);
216 memset(buffer, 0, COUNTOF(buffer));
217 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
218 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
220 SetLastError(0xdeadbeef);
221 memset(buffer, 0, COUNTOF(buffer));
222 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
223 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
224 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
225 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
227 SetLastError(0xdeadbeef);
228 memset(buffer, 0, COUNTOF(buffer));
229 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
230 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
231 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
234 struct neutralsublang_name2_t {
235 WCHAR name[3];
236 WCHAR sname[15];
237 LCID lcid;
238 LCID lcid_broken;
239 WCHAR sname_broken[15];
240 int todo;
243 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
244 { {'a','r',0}, {'a','r','-','S','A',0},
245 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
246 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
247 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
248 { {'d','e',0}, {'d','e','-','D','E',0},
249 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
250 { {'e','n',0}, {'e','n','-','U','S',0},
251 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
252 { {'e','s',0}, {'e','s','-','E','S',0},
253 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
254 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
255 {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
256 { {'g','a',0}, {'g','a','-','I','E',0},
257 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
258 { {'i','t',0}, {'i','t','-','I','T',0},
259 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
260 { {'m','s',0}, {'m','s','-','M','Y',0},
261 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
262 { {'n','l',0}, {'n','l','-','N','L',0},
263 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
264 { {'p','t',0}, {'p','t','-','B','R',0},
265 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
266 { {'s','r',0}, {'h','r','-','H','R',0},
267 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
268 { {'s','v',0}, {'s','v','-','S','E',0},
269 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
270 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
271 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
272 { {'z','h',0}, {'z','h','-','C','N',0},
273 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
274 { {0} }
277 static void test_GetLocaleInfoW(void)
279 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
280 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
281 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
282 WCHAR bufferW[80], buffer2W[80];
283 CHAR bufferA[80];
284 DWORD val;
285 DWORD ret;
286 INT i;
288 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
289 if (!ret) {
290 win_skip("GetLocaleInfoW() isn't implemented\n");
291 return;
294 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
295 ok(ret, "got %d\n", ret);
296 ok(val == lcid_en, "got 0x%08x\n", val);
298 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
299 if (ret)
301 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
302 'S','t','a','t','e','s',')',0};
303 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
304 static const WCHAR enW[] = {'e','n','-','U','S',0};
305 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
307 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
309 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
310 ok(ret, "got %d\n", ret);
311 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
312 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
314 skip("Non-English locale\n");
316 else
317 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
319 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
320 ok(ret, "got %d\n", ret);
321 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
322 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
324 skip("Non-English locale\n");
326 else
327 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
329 while (*ptr->name)
331 LANGID langid;
332 LCID lcid;
334 /* make neutral lcid */
335 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
336 lcid = MAKELCID(langid, SORT_DEFAULT);
338 val = 0;
339 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
340 todo_wine_if (ptr->todo & 0x1)
341 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
342 wine_dbgstr_w(ptr->name), val, ptr->lcid);
344 /* now check LOCALE_SNAME */
345 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
346 todo_wine_if (ptr->todo & 0x2)
347 ok(!lstrcmpW(bufferW, ptr->sname) ||
348 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
349 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
350 ptr++;
353 else
354 win_skip("English neutral locale not supported\n");
356 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
357 if (!ret) {
358 win_skip("LANG_RUSSIAN locale data unavailable\n");
359 return;
361 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
362 bufferW, COUNTOF(bufferW));
363 if (!ret) {
364 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
365 return;
368 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
369 bufferA[0] = 'a';
370 SetLastError(0xdeadbeef);
371 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
372 bufferA, COUNTOF(bufferA));
373 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
374 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
375 ok(GetLastError() == ERROR_INVALID_FLAGS,
376 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
378 bufferW[0] = 'a';
379 SetLastError(0xdeadbeef);
380 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
381 bufferW, COUNTOF(bufferW));
382 ok(ret == 0,
383 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
384 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
385 ok(GetLastError() == ERROR_INVALID_FLAGS,
386 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
388 /* yes, test empty 13 month entry too */
389 for (i = 0; i < 12; i++) {
390 bufferW[0] = 0;
391 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
392 bufferW, COUNTOF(bufferW));
393 ok(ret, "Expected non zero result\n");
394 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
395 ret, lstrlenW(bufferW));
396 buffer2W[0] = 0;
397 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
398 buffer2W, COUNTOF(buffer2W));
399 ok(ret, "Expected non zero result\n");
400 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
401 ret, lstrlenW(buffer2W));
403 ok(lstrcmpW(bufferW, buffer2W) != 0,
404 "Expected genitive name to differ, got the same for month %d\n", i+1);
406 /* for locale without genitive names nominative returned in both cases */
407 bufferW[0] = 0;
408 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
409 bufferW, COUNTOF(bufferW));
410 ok(ret, "Expected non zero result\n");
411 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
412 ret, lstrlenW(bufferW));
413 buffer2W[0] = 0;
414 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
415 buffer2W, COUNTOF(buffer2W));
416 ok(ret, "Expected non zero result\n");
417 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
418 ret, lstrlenW(buffer2W));
420 ok(lstrcmpW(bufferW, buffer2W) == 0,
421 "Expected same names, got different for month %d\n", i+1);
425 static void test_GetTimeFormatA(void)
427 int ret;
428 SYSTEMTIME curtime;
429 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
430 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
432 memset(&curtime, 2, sizeof(SYSTEMTIME));
433 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
434 SetLastError(0xdeadbeef);
435 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
436 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
437 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
439 curtime.wHour = 8;
440 curtime.wMinute = 56;
441 curtime.wSecond = 13;
442 curtime.wMilliseconds = 22;
443 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
444 SetLastError(0xdeadbeef);
445 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
446 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
447 EXPECT_LENA; EXPECT_EQA;
449 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
450 SetLastError(0xdeadbeef);
451 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
452 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
453 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
455 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
456 SetLastError(0xdeadbeef);
457 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
458 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
459 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
461 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
462 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
463 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
464 EXPECT_LENA;
466 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
467 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
468 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
469 EXPECT_LENA; EXPECT_EQA;
471 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
472 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
473 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
474 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
475 "Expected '', got '%s'\n", buffer );
477 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
478 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
479 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
480 EXPECT_LENA; EXPECT_EQA;
482 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
483 strcpy(Expected, "8:56 AM");
484 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
485 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
486 EXPECT_LENA; EXPECT_EQA;
488 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
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 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
492 "Expected '8.@:56AM', got '%s'\n", buffer );
494 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
495 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
496 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
497 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
498 "Expected '', got '%s'\n", buffer );
500 STRINGSA("t/tt", "A/AM"); /* AM time marker */
501 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
503 EXPECT_LENA; EXPECT_EQA;
505 curtime.wHour = 13;
506 STRINGSA("t/tt", "P/PM"); /* PM time marker */
507 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
508 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
509 EXPECT_LENA; EXPECT_EQA;
511 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
512 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &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("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
517 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &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", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
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 curtime.wHour = 14; /* change this to 14 or 2pm */
527 curtime.wMinute = 5;
528 curtime.wSecond = 3;
529 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 */
530 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
531 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
532 EXPECT_LENA; EXPECT_EQA;
534 curtime.wHour = 0;
535 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
536 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
537 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
538 EXPECT_LENA; EXPECT_EQA;
540 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
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 /* try to convert formatting strings with more than two letters
546 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
547 * NOTE: We expect any letter for which there is an upper case value
548 * we should see a replacement. For letters that DO NOT have
549 * upper case values we should see NO REPLACEMENT.
551 curtime.wHour = 8;
552 curtime.wMinute = 56;
553 curtime.wSecond = 13;
554 curtime.wMilliseconds = 22;
555 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
556 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
557 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
558 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
559 EXPECT_LENA; EXPECT_EQA;
561 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
562 strcpy(buffer, "text");
563 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
564 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
565 EXPECT_EQA;
567 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
568 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
569 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
570 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
571 EXPECT_LENA; EXPECT_EQA;
573 STRINGSA("'''", "'"); /* invalid quoted string */
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 /* test that msdn suggested single quotation usage works as expected */
579 STRINGSA("''''", "'"); /* single quote mark */
580 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
581 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
582 EXPECT_LENA; EXPECT_EQA;
584 STRINGSA("''HHHHHH", "08"); /* Normal use */
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 /* and test for normal use of the single quotation mark */
590 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
591 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
592 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
593 EXPECT_LENA; EXPECT_EQA;
595 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd 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("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
601 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
602 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
603 EXPECT_LENA; EXPECT_EQA;
605 curtime.wHour = 25;
606 STRINGSA("'123'tt", ""); /* Invalid time */
607 SetLastError(0xdeadbeef);
608 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
609 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
610 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
612 curtime.wHour = 12;
613 curtime.wMonth = 60; /* Invalid */
614 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
615 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
616 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
617 EXPECT_LENA; EXPECT_EQA;
620 static void test_GetTimeFormatEx(void)
622 int ret;
623 SYSTEMTIME curtime;
624 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
626 if (!pGetTimeFormatEx)
628 win_skip("GetTimeFormatEx not supported\n");
629 return;
632 memset(&curtime, 2, sizeof(SYSTEMTIME));
633 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
634 SetLastError(0xdeadbeef);
635 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
636 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
637 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
639 curtime.wHour = 8;
640 curtime.wMinute = 56;
641 curtime.wSecond = 13;
642 curtime.wMilliseconds = 22;
643 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
644 SetLastError(0xdeadbeef);
645 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
646 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
647 EXPECT_LENW; EXPECT_EQW;
649 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
650 SetLastError(0xdeadbeef);
651 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
652 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
653 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
655 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
656 SetLastError(0xdeadbeef);
657 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
658 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
659 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
661 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
662 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
663 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
664 EXPECT_LENW;
666 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
667 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
668 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
669 EXPECT_LENW; EXPECT_EQW;
671 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
672 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
673 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
674 EXPECT_LENW; EXPECT_EQW;
676 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
677 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
678 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
679 EXPECT_LENW; EXPECT_EQW;
681 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
682 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, 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.@:56AM"); /* Multiple delimiters */
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("s1s2s3", ""); /* Duplicate tokens */
692 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
693 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
694 EXPECT_LENW; EXPECT_EQW;
696 STRINGSW("t/tt", "A/AM"); /* AM time marker */
697 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
698 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
699 EXPECT_LENW; EXPECT_EQW;
701 curtime.wHour = 13;
702 STRINGSW("t/tt", "P/PM"); /* PM time marker */
703 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
704 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
705 EXPECT_LENW; EXPECT_EQW;
707 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
708 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &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("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
713 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &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", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
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 curtime.wHour = 14; /* change this to 14 or 2pm */
723 curtime.wMinute = 5;
724 curtime.wSecond = 3;
725 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 */
726 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
727 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
728 EXPECT_LENW; EXPECT_EQW;
730 curtime.wHour = 0;
731 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
732 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
733 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
734 EXPECT_LENW; EXPECT_EQW;
736 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
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 /* try to convert formatting strings with more than two letters
742 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
743 * NOTE: We expect any letter for which there is an upper case value
744 * we should see a replacement. For letters that DO NOT have
745 * upper case values we should see NO REPLACEMENT.
747 curtime.wHour = 8;
748 curtime.wMinute = 56;
749 curtime.wSecond = 13;
750 curtime.wMilliseconds = 22;
751 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
752 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
753 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
754 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
755 EXPECT_LENW; EXPECT_EQW;
757 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
758 lstrcpyW(buffer, Expected);
759 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
760 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
761 EXPECT_EQW;
763 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
764 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
765 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
766 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
767 EXPECT_LENW; EXPECT_EQW;
769 STRINGSW("'''", "'"); /* invalid quoted string */
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 /* test that msdn suggested single quotation usage works as expected */
775 STRINGSW("''''", "'"); /* single quote mark */
776 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
777 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
778 EXPECT_LENW; EXPECT_EQW;
780 STRINGSW("''HHHHHH", "08"); /* Normal use */
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 /* and test for normal use of the single quotation mark */
786 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
787 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
788 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
789 EXPECT_LENW; EXPECT_EQW;
791 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd 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("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
797 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
798 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
799 EXPECT_LENW; EXPECT_EQW;
801 curtime.wHour = 25;
802 STRINGSW("'123'tt", ""); /* Invalid time */
803 SetLastError(0xdeadbeef);
804 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
805 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
806 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
808 curtime.wHour = 12;
809 curtime.wMonth = 60; /* Invalid */
810 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
811 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
812 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
813 EXPECT_LENW; EXPECT_EQW;
816 static void test_GetDateFormatA(void)
818 int ret;
819 SYSTEMTIME curtime;
820 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
821 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
822 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
823 char Broken[BUFFER_SIZE];
824 char short_day[10], month[10], genitive_month[10];
826 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
827 STRINGSA("ddd',' MMM dd yy","");
828 SetLastError(0xdeadbeef);
829 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
830 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
831 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
833 curtime.wYear = 2002;
834 curtime.wMonth = 5;
835 curtime.wDay = 4;
836 curtime.wDayOfWeek = 3;
837 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
838 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
839 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
840 EXPECT_LENA; EXPECT_EQA;
842 /* Same as above but with LOCALE_NOUSEROVERRIDE */
843 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
844 SetLastError(0xdeadbeef);
845 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
846 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
847 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
848 EXPECT_EQA;
850 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
851 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
852 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
853 EXPECT_LENA; EXPECT_EQA;
855 curtime.wHour = 36; /* Invalid */
856 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
857 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
858 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
859 EXPECT_LENA; EXPECT_EQA;
861 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
862 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
863 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
864 EXPECT_EQA;
866 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
867 SetLastError(0xdeadbeef);
868 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
869 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
870 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
872 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
873 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
874 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
875 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
876 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
878 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
879 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
880 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
881 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
882 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
883 "got an unexpected date string '%s'\n", buffer);
885 /* test for expected DATE_YEARMONTH behavior with null format */
886 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
887 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
888 SetLastError(0xdeadbeef);
889 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
890 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
891 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
892 EXPECT_EQA;
894 /* Test that using invalid DATE_* flags results in the correct error */
895 /* and return values */
896 STRINGSA("m/d/y", ""); /* Invalid flags */
897 SetLastError(0xdeadbeef);
898 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
899 &curtime, input, buffer, COUNTOF(buffer));
900 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
901 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
903 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
904 if (!ret)
906 win_skip("LANG_RUSSIAN locale data unavailable\n");
907 return;
910 /* month part should be in genitive form */
911 strcpy(genitive_month, buffer + 2);
912 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
913 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
914 strcpy(month, buffer);
915 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
917 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
918 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
919 strcpy(short_day, buffer);
921 STRINGSA("dd MMMMddd dd", "");
922 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
923 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
924 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
925 EXPECT_EQA;
927 STRINGSA("MMMMddd dd", "");
928 sprintf(Expected, "%s%s 04", month, short_day);
929 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
930 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
931 EXPECT_EQA;
933 STRINGSA("MMMMddd", "");
934 sprintf(Expected, "%s%s", month, short_day);
935 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
936 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
937 EXPECT_EQA;
939 STRINGSA("MMMMdd", "");
940 sprintf(Expected, "%s04", genitive_month);
941 sprintf(Broken, "%s04", month);
942 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
943 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
944 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
945 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
946 "Expected '%s', got '%s'\n", Expected, buffer);
948 STRINGSA("MMMMdd ddd", "");
949 sprintf(Expected, "%s04 %s", genitive_month, short_day);
950 sprintf(Broken, "%s04 %s", month, short_day);
951 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
952 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
953 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
954 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
955 "Expected '%s', got '%s'\n", Expected, buffer);
957 STRINGSA("dd dddMMMM", "");
958 sprintf(Expected, "04 %s%s", short_day, month);
959 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
960 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
961 EXPECT_EQA;
963 STRINGSA("dd dddMMMM ddd MMMMdd", "");
964 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
965 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
966 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
967 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
968 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
969 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
970 "Expected '%s', got '%s'\n", Expected, buffer);
972 /* with literal part */
973 STRINGSA("ddd',' MMMM dd", "");
974 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
975 sprintf(Broken, "%s, %s 04", short_day, month);
976 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
977 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
978 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
979 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
980 "Expected '%s', got '%s'\n", Expected, buffer);
983 static void test_GetDateFormatEx(void)
985 int ret;
986 SYSTEMTIME curtime;
987 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
989 if (!pGetDateFormatEx)
991 win_skip("GetDateFormatEx not supported\n");
992 return;
995 STRINGSW("",""); /* If flags are set, then format must be NULL */
996 SetLastError(0xdeadbeef);
997 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
998 input, buffer, COUNTOF(buffer), NULL);
999 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1000 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1001 EXPECT_EQW;
1003 STRINGSW("",""); /* NULL buffer, len > 0 */
1004 SetLastError(0xdeadbeef);
1005 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1006 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1007 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1009 STRINGSW("",""); /* NULL buffer, len == 0 */
1010 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1011 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1012 EXPECT_LENW; EXPECT_EQW;
1014 STRINGSW("",""); /* Invalid flag combination */
1015 SetLastError(0xdeadbeef);
1016 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1017 input, NULL, 0, NULL);
1018 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1019 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1020 EXPECT_EQW;
1022 curtime.wYear = 2002;
1023 curtime.wMonth = 10;
1024 curtime.wDay = 23;
1025 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1026 curtime.wHour = 65432; /* Invalid */
1027 curtime.wMinute = 34512; /* Invalid */
1028 curtime.wSecond = 65535; /* Invalid */
1029 curtime.wMilliseconds = 12345;
1030 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1031 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1032 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1033 EXPECT_LENW; EXPECT_EQW;
1035 curtime.wYear = 2002;
1036 curtime.wMonth = 10;
1037 curtime.wDay = 23;
1038 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1039 curtime.wHour = 65432; /* Invalid */
1040 curtime.wMinute = 34512; /* Invalid */
1041 curtime.wSecond = 65535; /* Invalid */
1042 curtime.wMilliseconds = 12345;
1043 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1044 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1045 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1046 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1048 /* Limit tests */
1050 curtime.wYear = 1601;
1051 curtime.wMonth = 1;
1052 curtime.wDay = 1;
1053 curtime.wDayOfWeek = 0; /* Irrelevant */
1054 curtime.wHour = 0;
1055 curtime.wMinute = 0;
1056 curtime.wSecond = 0;
1057 curtime.wMilliseconds = 0;
1058 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1059 SetLastError(0xdeadbeef);
1060 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1061 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1062 EXPECT_LENW; EXPECT_EQW;
1064 curtime.wYear = 1600;
1065 curtime.wMonth = 12;
1066 curtime.wDay = 31;
1067 curtime.wDayOfWeek = 0; /* Irrelevant */
1068 curtime.wHour = 23;
1069 curtime.wMinute = 59;
1070 curtime.wSecond = 59;
1071 curtime.wMilliseconds = 999;
1072 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1073 SetLastError(0xdeadbeef);
1074 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1075 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1076 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1079 static void test_GetDateFormatW(void)
1081 int ret;
1082 SYSTEMTIME curtime;
1083 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1084 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1086 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1087 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1088 input, buffer, COUNTOF(buffer));
1089 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1091 win_skip("GetDateFormatW is not implemented\n");
1092 return;
1094 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1095 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1096 EXPECT_EQW;
1098 STRINGSW("",""); /* NULL buffer, len > 0 */
1099 SetLastError(0xdeadbeef);
1100 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1101 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1102 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1104 STRINGSW("",""); /* NULL buffer, len == 0 */
1105 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1106 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1107 EXPECT_LENW; EXPECT_EQW;
1109 curtime.wYear = 2002;
1110 curtime.wMonth = 10;
1111 curtime.wDay = 23;
1112 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1113 curtime.wHour = 65432; /* Invalid */
1114 curtime.wMinute = 34512; /* Invalid */
1115 curtime.wSecond = 65535; /* Invalid */
1116 curtime.wMilliseconds = 12345;
1117 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1118 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1119 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1120 EXPECT_LENW; EXPECT_EQW;
1122 /* Limit tests */
1124 curtime.wYear = 1601;
1125 curtime.wMonth = 1;
1126 curtime.wDay = 1;
1127 curtime.wDayOfWeek = 0; /* Irrelevant */
1128 curtime.wHour = 0;
1129 curtime.wMinute = 0;
1130 curtime.wSecond = 0;
1131 curtime.wMilliseconds = 0;
1132 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1133 SetLastError(0xdeadbeef);
1134 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1135 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1136 EXPECT_LENW; EXPECT_EQW;
1138 curtime.wYear = 1600;
1139 curtime.wMonth = 12;
1140 curtime.wDay = 31;
1141 curtime.wDayOfWeek = 0; /* Irrelevant */
1142 curtime.wHour = 23;
1143 curtime.wMinute = 59;
1144 curtime.wSecond = 59;
1145 curtime.wMilliseconds = 999;
1146 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1147 SetLastError(0xdeadbeef);
1148 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1149 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1150 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1154 #define CY_POS_LEFT 0
1155 #define CY_POS_RIGHT 1
1156 #define CY_POS_LEFT_SPACE 2
1157 #define CY_POS_RIGHT_SPACE 3
1159 static void test_GetCurrencyFormatA(void)
1161 static char szDot[] = { '.', '\0' };
1162 static char szComma[] = { ',', '\0' };
1163 static char szDollar[] = { '$', '\0' };
1164 int ret;
1165 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1166 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1167 CURRENCYFMTA format;
1169 memset(&format, 0, sizeof(format));
1171 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1172 SetLastError(0xdeadbeef);
1173 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1174 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1175 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1177 STRINGSA("23,53",""); /* Invalid character --> Error */
1178 SetLastError(0xdeadbeef);
1179 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1180 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1181 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1183 STRINGSA("--",""); /* Double '-' --> Error */
1184 SetLastError(0xdeadbeef);
1185 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1186 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1187 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1189 STRINGSA("0-",""); /* Trailing '-' --> Error */
1190 SetLastError(0xdeadbeef);
1191 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1192 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1193 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1195 STRINGSA("0..",""); /* Double '.' --> Error */
1196 SetLastError(0xdeadbeef);
1197 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1198 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1199 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1201 STRINGSA(" 0.1",""); /* Leading space --> Error */
1202 SetLastError(0xdeadbeef);
1203 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1204 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1205 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1207 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1208 SetLastError(0xdeadbeef);
1209 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1210 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1211 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1213 STRINGSA("2353",""); /* Format and flags given --> Error */
1214 SetLastError(0xdeadbeef);
1215 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1216 ok( !ret, "Expected ret == 0, got %d\n", ret);
1217 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1218 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1220 STRINGSA("2353",""); /* Invalid format --> Error */
1221 SetLastError(0xdeadbeef);
1222 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1223 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1224 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1226 STRINGSA("2353","$2,353.00"); /* Valid number */
1227 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1228 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1229 EXPECT_LENA; EXPECT_EQA;
1231 STRINGSA("-2353","($2,353.00)"); /* Valid negative 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.1","$2,353.10"); /* Valid real 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.111","$2,353.11"); /* Too many DP --> Truncated */
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.119","$2,353.12"); /* Too many DP --> Rounded */
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 format.NumDigits = 0; /* No decimal separator */
1252 format.LeadingZero = 0;
1253 format.Grouping = 0; /* No grouping char */
1254 format.NegativeOrder = 0;
1255 format.PositiveOrder = CY_POS_LEFT;
1256 format.lpDecimalSep = szDot;
1257 format.lpThousandSep = szComma;
1258 format.lpCurrencySymbol = szDollar;
1260 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1261 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1262 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1263 EXPECT_LENA; EXPECT_EQA;
1265 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1266 STRINGSA("2353","$2353.0");
1267 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1268 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1269 EXPECT_LENA; EXPECT_EQA;
1271 format.Grouping = 2; /* Group by 100's */
1272 STRINGSA("2353","$23,53.0");
1273 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1274 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1275 EXPECT_LENA; EXPECT_EQA;
1277 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1278 format.Grouping = 3;
1279 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1280 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1281 EXPECT_LENA; EXPECT_EQA;
1283 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1284 format.NegativeOrder = 2;
1285 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1286 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1287 EXPECT_LENA; EXPECT_EQA;
1289 format.LeadingZero = 1; /* Always provide leading zero */
1290 STRINGSA(".5","$0.5");
1291 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1292 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1293 EXPECT_LENA; EXPECT_EQA;
1295 format.PositiveOrder = CY_POS_RIGHT;
1296 STRINGSA("1","1.0$");
1297 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1298 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1299 EXPECT_LENA; EXPECT_EQA;
1301 format.PositiveOrder = CY_POS_LEFT_SPACE;
1302 STRINGSA("1","$ 1.0");
1303 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1304 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1305 EXPECT_LENA; EXPECT_EQA;
1307 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1308 STRINGSA("1","1.0 $");
1309 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1310 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1311 EXPECT_LENA; EXPECT_EQA;
1313 format.NegativeOrder = 0;
1314 STRINGSA("-1","($1.0)");
1315 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1316 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1317 EXPECT_LENA; EXPECT_EQA;
1319 format.NegativeOrder = 1;
1320 STRINGSA("-1","-$1.0");
1321 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1322 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1323 EXPECT_LENA; EXPECT_EQA;
1325 format.NegativeOrder = 2;
1326 STRINGSA("-1","$-1.0");
1327 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1328 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1329 EXPECT_LENA; EXPECT_EQA;
1331 format.NegativeOrder = 3;
1332 STRINGSA("-1","$1.0-");
1333 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1334 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1335 EXPECT_LENA; EXPECT_EQA;
1337 format.NegativeOrder = 4;
1338 STRINGSA("-1","(1.0$)");
1339 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1340 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1341 EXPECT_LENA; EXPECT_EQA;
1343 format.NegativeOrder = 5;
1344 STRINGSA("-1","-1.0$");
1345 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1346 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1347 EXPECT_LENA; EXPECT_EQA;
1349 format.NegativeOrder = 6;
1350 STRINGSA("-1","1.0-$");
1351 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1352 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1353 EXPECT_LENA; EXPECT_EQA;
1355 format.NegativeOrder = 7;
1356 STRINGSA("-1","1.0$-");
1357 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1358 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1359 EXPECT_LENA; EXPECT_EQA;
1361 format.NegativeOrder = 8;
1362 STRINGSA("-1","-1.0 $");
1363 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1364 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1365 EXPECT_LENA; EXPECT_EQA;
1367 format.NegativeOrder = 9;
1368 STRINGSA("-1","-$ 1.0");
1369 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1370 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1371 EXPECT_LENA; EXPECT_EQA;
1373 format.NegativeOrder = 10;
1374 STRINGSA("-1","1.0 $-");
1375 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1376 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1377 EXPECT_LENA; EXPECT_EQA;
1379 format.NegativeOrder = 11;
1380 STRINGSA("-1","$ 1.0-");
1381 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1382 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1383 EXPECT_LENA; EXPECT_EQA;
1385 format.NegativeOrder = 12;
1386 STRINGSA("-1","$ -1.0");
1387 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1388 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1389 EXPECT_LENA; EXPECT_EQA;
1391 format.NegativeOrder = 13;
1392 STRINGSA("-1","1.0- $");
1393 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1394 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1395 EXPECT_LENA; EXPECT_EQA;
1397 format.NegativeOrder = 14;
1398 STRINGSA("-1","($ 1.0)");
1399 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1400 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1401 EXPECT_LENA; EXPECT_EQA;
1403 format.NegativeOrder = 15;
1404 STRINGSA("-1","(1.0 $)");
1405 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1406 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1407 EXPECT_LENA; EXPECT_EQA;
1410 #define NEG_PARENS 0 /* "(1.1)" */
1411 #define NEG_LEFT 1 /* "-1.1" */
1412 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1413 #define NEG_RIGHT 3 /* "1.1-" */
1414 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1416 static void test_GetNumberFormatA(void)
1418 static char szDot[] = { '.', '\0' };
1419 static char szComma[] = { ',', '\0' };
1420 int ret;
1421 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1422 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1423 NUMBERFMTA format;
1425 memset(&format, 0, sizeof(format));
1427 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1428 SetLastError(0xdeadbeef);
1429 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1430 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1431 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1433 STRINGSA("23,53",""); /* Invalid character --> Error */
1434 SetLastError(0xdeadbeef);
1435 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1436 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1437 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1439 STRINGSA("--",""); /* Double '-' --> Error */
1440 SetLastError(0xdeadbeef);
1441 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1442 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1443 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1445 STRINGSA("0-",""); /* Trailing '-' --> Error */
1446 SetLastError(0xdeadbeef);
1447 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1448 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1449 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1451 STRINGSA("0..",""); /* Double '.' --> Error */
1452 SetLastError(0xdeadbeef);
1453 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1454 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1455 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1457 STRINGSA(" 0.1",""); /* Leading space --> Error */
1458 SetLastError(0xdeadbeef);
1459 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1460 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1461 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1463 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1464 SetLastError(0xdeadbeef);
1465 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1466 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1467 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1469 STRINGSA("2353",""); /* Format and flags given --> Error */
1470 SetLastError(0xdeadbeef);
1471 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1472 ok( !ret, "Expected ret == 0, got %d\n", ret);
1473 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1474 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1476 STRINGSA("2353",""); /* Invalid format --> Error */
1477 SetLastError(0xdeadbeef);
1478 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1479 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1480 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1482 STRINGSA("2353","2,353.00"); /* Valid number */
1483 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1484 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1485 EXPECT_LENA; EXPECT_EQA;
1487 STRINGSA("-2353","-2,353.00"); /* Valid negative 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("-353","-353.00"); /* test for off by one error in grouping */
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("2353.1","2,353.10"); /* Valid real number */
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.111","2,353.11"); /* Too many DP --> Truncated */
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.119","2,353.12"); /* Too many DP --> Rounded */
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 format.NumDigits = 0; /* No decimal separator */
1513 format.LeadingZero = 0;
1514 format.Grouping = 0; /* No grouping char */
1515 format.NegativeOrder = 0;
1516 format.lpDecimalSep = szDot;
1517 format.lpThousandSep = szComma;
1519 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1520 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1521 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1522 EXPECT_LENA; EXPECT_EQA;
1524 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1525 STRINGSA("2353","2353.0");
1526 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1527 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1528 EXPECT_LENA; EXPECT_EQA;
1530 format.Grouping = 2; /* Group by 100's */
1531 STRINGSA("2353","23,53.0");
1532 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1533 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1534 EXPECT_LENA; EXPECT_EQA;
1536 STRINGSA("235","235.0"); /* Grouping of a positive number */
1537 format.Grouping = 3;
1538 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1539 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1540 EXPECT_LENA; EXPECT_EQA;
1542 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1543 format.NegativeOrder = NEG_LEFT;
1544 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1545 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1546 EXPECT_LENA; EXPECT_EQA;
1548 format.LeadingZero = 1; /* Always provide leading zero */
1549 STRINGSA(".5","0.5");
1550 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1551 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1552 EXPECT_LENA; EXPECT_EQA;
1554 format.NegativeOrder = NEG_PARENS;
1555 STRINGSA("-1","(1.0)");
1556 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1557 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1558 EXPECT_LENA; EXPECT_EQA;
1560 format.NegativeOrder = NEG_LEFT;
1561 STRINGSA("-1","-1.0");
1562 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1563 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1564 EXPECT_LENA; EXPECT_EQA;
1566 format.NegativeOrder = NEG_LEFT_SPACE;
1567 STRINGSA("-1","- 1.0");
1568 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1569 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1570 EXPECT_LENA; EXPECT_EQA;
1572 format.NegativeOrder = NEG_RIGHT;
1573 STRINGSA("-1","1.0-");
1574 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1575 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1576 EXPECT_LENA; EXPECT_EQA;
1578 format.NegativeOrder = NEG_RIGHT_SPACE;
1579 STRINGSA("-1","1.0 -");
1580 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1581 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1582 EXPECT_LENA; EXPECT_EQA;
1584 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1586 if (IsValidLocale(lcid, 0))
1588 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1589 Expected[3] = 160; /* Non breaking space */
1590 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1591 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1592 EXPECT_LENA; EXPECT_EQA;
1596 static void test_GetNumberFormatEx(void)
1598 int ret;
1599 NUMBERFMTW format;
1600 static WCHAR dotW[] = {'.',0};
1601 static WCHAR commaW[] = {',',0};
1602 static const WCHAR enW[] = {'e','n','-','U','S',0};
1603 static const WCHAR frW[] = {'f','r','-','F','R',0};
1604 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1605 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1607 if (!pGetNumberFormatEx)
1609 win_skip("GetNumberFormatEx is not available.\n");
1610 return;
1613 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1614 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1615 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1616 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1618 STRINGSW("23,53",""); /* Invalid character --> Error */
1619 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1620 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1621 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1623 STRINGSW("--",""); /* Double '-' --> 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("0-",""); /* Trailing '-' --> 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..",""); /* Double '.' --> 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.1",""); /* Leading space --> 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("1234","1"); /* Length too small --> Write up to length chars */
1644 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1645 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1646 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1648 STRINGSW("23",""); /* Bogus locale --> Error */
1649 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1650 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1651 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1653 memset(&format, 0, sizeof(format));
1655 STRINGSW("2353",""); /* Format and flags given --> Error */
1656 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1657 ok( !ret, "Expected ret == 0, got %d\n", ret);
1658 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1659 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1661 STRINGSW("2353",""); /* Invalid format --> Error */
1662 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1663 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1664 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1666 STRINGSW("2353","2,353.00"); /* Valid number */
1667 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1668 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1669 EXPECT_LENW; EXPECT_EQW;
1671 STRINGSW("-2353","-2,353.00"); /* Valid negative 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("-353","-353.00"); /* test for off by one error in grouping */
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("2353.1","2,353.10"); /* Valid real number */
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.111","2,353.11"); /* Too many DP --> Truncated */
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.119","2,353.12"); /* Too many DP --> Rounded */
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 format.NumDigits = 0; /* No decimal separator */
1697 format.LeadingZero = 0;
1698 format.Grouping = 0; /* No grouping char */
1699 format.NegativeOrder = 0;
1700 format.lpDecimalSep = dotW;
1701 format.lpThousandSep = commaW;
1703 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1704 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1705 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1706 EXPECT_LENW; EXPECT_EQW;
1708 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1709 STRINGSW("2353","2353.0");
1710 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1711 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1712 EXPECT_LENW; EXPECT_EQW;
1714 format.Grouping = 2; /* Group by 100's */
1715 STRINGSW("2353","23,53.0");
1716 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1718 EXPECT_LENW; EXPECT_EQW;
1720 STRINGSW("235","235.0"); /* Grouping of a positive number */
1721 format.Grouping = 3;
1722 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1723 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1724 EXPECT_LENW; EXPECT_EQW;
1726 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1727 format.NegativeOrder = NEG_LEFT;
1728 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1729 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1730 EXPECT_LENW; EXPECT_EQW;
1732 format.LeadingZero = 1; /* Always provide leading zero */
1733 STRINGSW(".5","0.5");
1734 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1735 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1736 EXPECT_LENW; EXPECT_EQW;
1738 format.NegativeOrder = NEG_PARENS;
1739 STRINGSW("-1","(1.0)");
1740 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1741 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1742 EXPECT_LENW; EXPECT_EQW;
1744 format.NegativeOrder = NEG_LEFT;
1745 STRINGSW("-1","-1.0");
1746 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1747 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1748 EXPECT_LENW; EXPECT_EQW;
1750 format.NegativeOrder = NEG_LEFT_SPACE;
1751 STRINGSW("-1","- 1.0");
1752 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1753 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1754 EXPECT_LENW; EXPECT_EQW;
1756 format.NegativeOrder = NEG_RIGHT;
1757 STRINGSW("-1","1.0-");
1758 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1759 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1760 EXPECT_LENW; EXPECT_EQW;
1762 format.NegativeOrder = NEG_RIGHT_SPACE;
1763 STRINGSW("-1","1.0 -");
1764 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1765 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1766 EXPECT_LENW; EXPECT_EQW;
1768 if (pIsValidLocaleName(frW))
1770 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1771 Expected[3] = 160; /* Non breaking space */
1772 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1773 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1774 EXPECT_LENW; EXPECT_EQW;
1778 struct comparestringa_entry {
1779 LCID lcid;
1780 DWORD flags;
1781 const char *first;
1782 int first_len;
1783 const char *second;
1784 int second_len;
1785 int ret;
1788 static const struct comparestringa_entry comparestringa_data[] = {
1789 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1790 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1791 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1792 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1793 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1794 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1797 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1798 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1799 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1808 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1809 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1810 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1811 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1812 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1813 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1814 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1818 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1820 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1821 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1823 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1824 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1825 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1826 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1827 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1828 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1835 static void test_CompareStringA(void)
1837 int ret, i;
1838 char a[256];
1839 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1841 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1843 const struct comparestringa_entry *entry = &comparestringa_data[i];
1845 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1846 entry->second, entry->second_len);
1847 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1850 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1851 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1853 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1854 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1856 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1857 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1859 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1860 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1862 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
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 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1868 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1870 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1871 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1873 /* test for CompareStringA flags */
1874 SetLastError(0xdeadbeef);
1875 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1876 ok(GetLastError() == ERROR_INVALID_FLAGS,
1877 "unexpected error code %d\n", GetLastError());
1878 ok(!ret, "CompareStringA must fail with invalid flag\n");
1880 SetLastError(0xdeadbeef);
1881 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1882 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1883 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1884 /* end of test for CompareStringA flags */
1886 ret = lstrcmpA("", "");
1887 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1889 ret = lstrcmpA(NULL, NULL);
1890 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1892 ret = lstrcmpA("", NULL);
1893 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1895 ret = lstrcmpA(NULL, "");
1896 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1899 if (0) { /* this requires collation table patch to make it MS compatible */
1900 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1901 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1903 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1904 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1906 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1907 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1909 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1910 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1912 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1913 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1915 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1916 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1918 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1919 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1921 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1922 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1924 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1925 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1927 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1928 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1930 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1931 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1933 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1934 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1938 /* WinXP handles embedded NULLs differently than earlier versions */
1939 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1940 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1942 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1943 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);
1945 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1946 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1948 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1949 ok(ret == CSTR_EQUAL || /* win2k */
1950 ret == CSTR_GREATER_THAN,
1951 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1953 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1954 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1956 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1957 todo_wine ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1959 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1960 todo_wine ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1962 ret = lstrcmpiA("#", ".");
1963 todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1965 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1967 /* \xB9 character lies between a and b */
1968 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1969 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1970 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1971 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1973 memset(a, 'a', sizeof(a));
1974 SetLastError(0xdeadbeef);
1975 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1976 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1977 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1980 static void test_CompareStringW(void)
1982 WCHAR *str1, *str2;
1983 SYSTEM_INFO si;
1984 DWORD old_prot;
1985 BOOL success;
1986 char *buf;
1987 int ret;
1989 GetSystemInfo(&si);
1990 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1991 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1992 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1993 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1994 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1995 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1997 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
1998 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
1999 *str1 = 'A';
2000 *str2 = 'B';
2002 /* CompareStringW should abort on the first non-matching character */
2003 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2004 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2006 success = VirtualFree(buf, 0, MEM_RELEASE);
2007 ok(success, "VirtualFree failed with %u\n", GetLastError());
2010 struct comparestringex_test {
2011 const char *locale;
2012 DWORD flags;
2013 const WCHAR first[2];
2014 const WCHAR second[2];
2015 INT ret;
2016 INT broken;
2017 BOOL todo;
2020 static const struct comparestringex_test comparestringex_tests[] = {
2021 /* default behavior */
2022 { /* 0 */
2023 "tr-TR", 0,
2024 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2026 { /* 1 */
2027 "tr-TR", 0,
2028 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2030 { /* 2 */
2031 "tr-TR", 0,
2032 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2034 { /* 3 */
2035 "tr-TR", 0,
2036 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2038 { /* 4 */
2039 "tr-TR", 0,
2040 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2042 { /* 5 */
2043 "tr-TR", 0,
2044 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2046 /* with NORM_IGNORECASE */
2047 { /* 6 */
2048 "tr-TR", NORM_IGNORECASE,
2049 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2051 { /* 7 */
2052 "tr-TR", NORM_IGNORECASE,
2053 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2055 { /* 8 */
2056 "tr-TR", NORM_IGNORECASE,
2057 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2059 { /* 9 */
2060 "tr-TR", NORM_IGNORECASE,
2061 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2063 { /* 10 */
2064 "tr-TR", NORM_IGNORECASE,
2065 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2067 { /* 11 */
2068 "tr-TR", NORM_IGNORECASE,
2069 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2071 /* with NORM_LINGUISTIC_CASING */
2072 { /* 12 */
2073 "tr-TR", NORM_LINGUISTIC_CASING,
2074 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2076 { /* 13 */
2077 "tr-TR", NORM_LINGUISTIC_CASING,
2078 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2080 { /* 14 */
2081 "tr-TR", NORM_LINGUISTIC_CASING,
2082 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2084 { /* 15 */
2085 "tr-TR", NORM_LINGUISTIC_CASING,
2086 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2088 { /* 16 */
2089 "tr-TR", NORM_LINGUISTIC_CASING,
2090 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2092 { /* 17 */
2093 "tr-TR", NORM_LINGUISTIC_CASING,
2094 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2096 /* with LINGUISTIC_IGNORECASE */
2097 { /* 18 */
2098 "tr-TR", LINGUISTIC_IGNORECASE,
2099 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2101 { /* 19 */
2102 "tr-TR", LINGUISTIC_IGNORECASE,
2103 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2105 { /* 20 */
2106 "tr-TR", LINGUISTIC_IGNORECASE,
2107 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2109 { /* 21 */
2110 "tr-TR", LINGUISTIC_IGNORECASE,
2111 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2113 { /* 22 */
2114 "tr-TR", LINGUISTIC_IGNORECASE,
2115 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2117 { /* 23 */
2118 "tr-TR", LINGUISTIC_IGNORECASE,
2119 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2121 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2122 { /* 24 */
2123 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2124 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2126 { /* 25 */
2127 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2128 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2130 { /* 26 */
2131 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2132 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2134 { /* 27 */
2135 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2136 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2138 { /* 28 */
2139 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2140 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2142 { /* 29 */
2143 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2144 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2146 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2147 { /* 30 */
2148 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2149 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2151 { /* 31 */
2152 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2153 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2155 { /* 32 */
2156 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2157 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2159 { /* 33 */
2160 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2161 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2163 { /* 34 */
2164 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2165 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2167 { /* 35 */
2168 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2169 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2173 static void test_CompareStringEx(void)
2175 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2176 WCHAR locale[6];
2177 INT ret, i;
2179 /* CompareStringEx is only available on Vista+ */
2180 if (!pCompareStringEx)
2182 win_skip("CompareStringEx not supported\n");
2183 return;
2186 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2188 const struct comparestringex_test *e = &comparestringex_tests[i];
2190 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2191 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2192 todo_wine_if (e->todo)
2193 ok(ret == e->ret || broken(ret == e->broken),
2194 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2199 static const DWORD lcmap_invalid_flags[] = {
2201 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2202 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2203 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2204 LCMAP_LOWERCASE | SORT_STRINGSORT,
2205 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2206 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2207 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2208 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2211 static void test_LCMapStringA(void)
2213 int ret, ret2, i;
2214 char buf[256], buf2[256];
2215 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2216 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2217 static const char symbols_stripped[] = "justateststring1";
2219 SetLastError(0xdeadbeef);
2220 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2221 lower_case, -1, buf, sizeof(buf));
2222 ok(ret == lstrlenA(lower_case) + 1,
2223 "ret %d, error %d, expected value %d\n",
2224 ret, GetLastError(), lstrlenA(lower_case) + 1);
2225 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2227 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2228 upper_case, -1, buf, sizeof(buf));
2229 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2230 ok(GetLastError() == ERROR_INVALID_FLAGS,
2231 "unexpected error code %d\n", GetLastError());
2233 /* test invalid flag combinations */
2234 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2235 lstrcpyA(buf, "foo");
2236 SetLastError(0xdeadbeef);
2237 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2238 lower_case, -1, buf, sizeof(buf));
2239 ok(GetLastError() == ERROR_INVALID_FLAGS,
2240 "LCMapStringA (flag %08x) unexpected error code %d\n",
2241 lcmap_invalid_flags[i], GetLastError());
2242 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2243 lcmap_invalid_flags[i], ret);
2246 /* test LCMAP_LOWERCASE */
2247 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2248 upper_case, -1, buf, sizeof(buf));
2249 ok(ret == lstrlenA(upper_case) + 1,
2250 "ret %d, error %d, expected value %d\n",
2251 ret, GetLastError(), lstrlenA(upper_case) + 1);
2252 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2254 /* test LCMAP_UPPERCASE */
2255 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2256 lower_case, -1, buf, sizeof(buf));
2257 ok(ret == lstrlenA(lower_case) + 1,
2258 "ret %d, error %d, expected value %d\n",
2259 ret, GetLastError(), lstrlenA(lower_case) + 1);
2260 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2262 /* test buffer overflow */
2263 SetLastError(0xdeadbeef);
2264 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2265 lower_case, -1, buf, 4);
2266 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2267 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2269 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2270 lstrcpyA(buf, lower_case);
2271 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2272 buf, -1, buf, sizeof(buf));
2273 if (!ret) /* Win9x */
2274 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2275 else
2277 ok(ret == lstrlenA(lower_case) + 1,
2278 "ret %d, error %d, expected value %d\n",
2279 ret, GetLastError(), lstrlenA(lower_case) + 1);
2280 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2282 lstrcpyA(buf, upper_case);
2283 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2284 buf, -1, buf, sizeof(buf));
2285 if (!ret) /* Win9x */
2286 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2287 else
2289 ok(ret == lstrlenA(upper_case) + 1,
2290 "ret %d, error %d, expected value %d\n",
2291 ret, GetLastError(), lstrlenA(lower_case) + 1);
2292 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2295 /* otherwise src == dst should fail */
2296 SetLastError(0xdeadbeef);
2297 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2298 buf, 10, buf, sizeof(buf));
2299 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2300 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2301 "unexpected error code %d\n", GetLastError());
2302 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2304 /* test whether '\0' is always appended */
2305 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2306 upper_case, -1, buf, sizeof(buf));
2307 ok(ret, "LCMapStringA must succeed\n");
2308 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2309 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2310 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2311 ok(ret2, "LCMapStringA must succeed\n");
2312 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2313 ok(ret == ret2, "lengths of sort keys must be equal\n");
2314 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2316 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2317 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2318 upper_case, -1, buf, sizeof(buf));
2319 ok(ret, "LCMapStringA must succeed\n");
2320 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2321 lower_case, -1, buf2, sizeof(buf2));
2322 ok(ret2, "LCMapStringA must succeed\n");
2323 ok(ret == ret2, "lengths of sort keys must be equal\n");
2324 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2326 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2327 results from plain LCMAP_SORTKEY on Vista */
2329 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2330 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2331 lower_case, -1, buf, sizeof(buf));
2332 ok(ret, "LCMapStringA must succeed\n");
2333 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2334 symbols_stripped, -1, buf2, sizeof(buf2));
2335 ok(ret2, "LCMapStringA must succeed\n");
2336 ok(ret == ret2, "lengths of sort keys must be equal\n");
2337 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2339 /* test NORM_IGNORENONSPACE */
2340 lstrcpyA(buf, "foo");
2341 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2342 lower_case, -1, buf, sizeof(buf));
2343 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2344 lstrlenA(lower_case) + 1, ret);
2345 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2347 /* test NORM_IGNORESYMBOLS */
2348 lstrcpyA(buf, "foo");
2349 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2350 lower_case, -1, buf, sizeof(buf));
2351 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2352 lstrlenA(symbols_stripped) + 1, ret);
2353 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2355 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2356 lstrcpyA(buf, "foo");
2357 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2358 lower_case, -1, buf, sizeof(buf));
2359 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2360 lstrlenA(symbols_stripped) + 1, ret);
2361 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2363 /* test srclen = 0 */
2364 SetLastError(0xdeadbeef);
2365 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2366 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2367 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2368 "unexpected error code %d\n", GetLastError());
2371 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2373 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
2375 const static WCHAR japanese_text[] = {
2376 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2377 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2379 const static WCHAR hiragana_text[] = {
2380 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2381 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2383 const static WCHAR katakana_text[] = {
2384 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2385 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2387 const static WCHAR halfwidth_text[] = {
2388 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2389 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2391 int ret, ret2, i;
2392 WCHAR buf[256], buf2[256];
2393 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2395 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2396 ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2397 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2398 todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2399 "%s ret %d, error %d, expected value %d\n", func_name,
2400 ret, GetLastError(), lstrlenW(title_case) + 1);
2401 todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
2402 "Expected title case string\n");
2404 /* test invalid flag combinations */
2405 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2406 lstrcpyW(buf, fooW);
2407 SetLastError(0xdeadbeef);
2408 ret = func_ptr(lcmap_invalid_flags[i],
2409 lower_case, -1, buf, sizeof(buf));
2410 ok(GetLastError() == ERROR_INVALID_FLAGS,
2411 "%s (flag %08x) unexpected error code %d\n",
2412 func_name, lcmap_invalid_flags[i], GetLastError());
2413 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2414 func_name, lcmap_invalid_flags[i], ret);
2417 /* test LCMAP_LOWERCASE */
2418 ret = func_ptr(LCMAP_LOWERCASE,
2419 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2420 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2421 ret, GetLastError(), lstrlenW(upper_case) + 1);
2422 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2424 /* test LCMAP_UPPERCASE */
2425 ret = func_ptr(LCMAP_UPPERCASE,
2426 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2427 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2428 ret, GetLastError(), lstrlenW(lower_case) + 1);
2429 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2431 /* test LCMAP_HIRAGANA */
2432 ret = func_ptr(LCMAP_HIRAGANA,
2433 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2434 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2435 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2436 todo_wine ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2438 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2439 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2440 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2441 ret, GetLastError());
2442 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2443 todo_wine ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2444 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2446 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2447 ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
2448 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2449 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2450 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2451 todo_wine ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2453 /* test LCMAP_FULLWIDTH */
2454 ret = func_ptr(LCMAP_FULLWIDTH,
2455 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2456 todo_wine ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2457 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2458 todo_wine ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2460 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2461 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2463 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2464 (half-width katakana is converted into full-wdith hiragana) */
2465 ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
2466 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2467 todo_wine ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2468 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2469 todo_wine ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2471 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2472 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2474 /* test LCMAP_HALFWIDTH */
2475 ret = func_ptr(LCMAP_HALFWIDTH,
2476 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2477 todo_wine ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2478 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2479 todo_wine ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2481 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2482 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2484 /* test buffer overflow */
2485 SetLastError(0xdeadbeef);
2486 ret = func_ptr(LCMAP_UPPERCASE,
2487 lower_case, -1, buf, 4);
2488 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2489 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2491 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2492 Thus, it requires two WCHARs. */
2493 buf[0] = 0x30ac;
2494 SetLastError(0xdeadbeef);
2495 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2496 todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2497 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2499 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2500 lstrcpyW(buf, lower_case);
2501 ret = func_ptr(LCMAP_UPPERCASE,
2502 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2503 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2504 ret, GetLastError(), lstrlenW(lower_case) + 1);
2505 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2507 lstrcpyW(buf, upper_case);
2508 ret = func_ptr(LCMAP_LOWERCASE,
2509 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2510 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2511 ret, GetLastError(), lstrlenW(lower_case) + 1);
2512 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2514 /* otherwise src == dst should fail */
2515 SetLastError(0xdeadbeef);
2516 ret = func_ptr(LCMAP_SORTKEY | LCMAP_UPPERCASE,
2517 buf, 10, buf, sizeof(buf));
2518 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2519 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2520 "%s unexpected error code %d\n", func_name, GetLastError());
2521 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2523 /* test whether '\0' is always appended */
2524 ret = func_ptr(LCMAP_SORTKEY,
2525 upper_case, -1, buf, sizeof(buf));
2526 ok(ret, "%s func_ptr must succeed\n", func_name);
2527 ret2 = func_ptr(LCMAP_SORTKEY,
2528 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2529 ok(ret, "%s func_ptr must succeed\n", func_name);
2530 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2531 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2533 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2534 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORECASE,
2535 upper_case, -1, buf, sizeof(buf));
2536 ok(ret, "%s func_ptr must succeed\n", func_name);
2537 ret2 = func_ptr(LCMAP_SORTKEY,
2538 lower_case, -1, buf2, sizeof(buf2));
2539 ok(ret2, "%s func_ptr must succeed\n", func_name);
2540 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2541 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2543 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2544 results from plain LCMAP_SORTKEY on Vista */
2546 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2547 ret = func_ptr(LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2548 lower_case, -1, buf, sizeof(buf));
2549 ok(ret, "%s func_ptr must succeed\n", func_name);
2550 ret2 = func_ptr(LCMAP_SORTKEY,
2551 symbols_stripped, -1, buf2, sizeof(buf2));
2552 ok(ret2, "%s func_ptr must succeed\n", func_name);
2553 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2554 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2556 /* test NORM_IGNORENONSPACE */
2557 lstrcpyW(buf, fooW);
2558 ret = func_ptr(NORM_IGNORENONSPACE,
2559 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2560 ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2561 lstrlenW(lower_case) + 1, ret);
2562 ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2564 /* test NORM_IGNORESYMBOLS */
2565 lstrcpyW(buf, fooW);
2566 ret = func_ptr(NORM_IGNORESYMBOLS,
2567 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2568 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2569 lstrlenW(symbols_stripped) + 1, ret);
2570 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2572 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2573 lstrcpyW(buf, fooW);
2574 ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2575 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2576 ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2577 lstrlenW(symbols_stripped) + 1, ret);
2578 ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2580 /* test srclen = 0 */
2581 SetLastError(0xdeadbeef);
2582 ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2583 ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2584 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2585 "%s unexpected error code %d\n", func_name, GetLastError());
2588 static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2590 return LCMapStringW(LOCALE_USER_DEFAULT, flags, src, srclen, dst, dstlen);
2593 static void test_LCMapStringW(void)
2595 int ret;
2596 WCHAR buf[256];
2598 trace("testing LCMapStringW\n");
2600 SetLastError(0xdeadbeef);
2601 ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2602 todo_wine {
2603 ok(!ret, "LCMapStringW should fail with bad lcid\n");
2604 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2607 test_lcmapstring_unicode(LCMapStringW_wrapper, "LCMapStringW:");
2610 static INT LCMapStringEx_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen)
2612 return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2615 static void test_LCMapStringEx(void)
2617 int ret;
2618 WCHAR buf[256];
2620 if (!pLCMapStringEx)
2622 win_skip( "LCMapStringEx not available\n" );
2623 return;
2626 trace("testing LCMapStringEx\n");
2628 SetLastError(0xdeadbeef);
2629 ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
2630 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2631 todo_wine {
2632 ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2633 ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2636 /* test reserved parameters */
2637 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2638 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2639 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2640 ret, GetLastError(), lstrlenW(upper_case) + 1);
2641 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2643 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2644 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2645 ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2646 ret, GetLastError(), lstrlenW(upper_case) + 1);
2647 ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2649 /* crashes on native */
2650 if(0)
2651 ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2652 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2654 test_lcmapstring_unicode(LCMapStringEx_wrapper, "LCMapStringEx:");
2657 struct neutralsublang_name_t {
2658 WCHAR name[3];
2659 LCID lcid;
2660 int todo;
2663 static const struct neutralsublang_name_t neutralsublang_names[] = {
2664 { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2665 { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2666 { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2667 { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2668 { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
2669 { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2670 { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2671 { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2672 { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2673 { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2674 { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2675 { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2676 { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2677 { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
2678 { {0} }
2681 static void test_LocaleNameToLCID(void)
2683 LCID lcid;
2684 INT ret;
2685 WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
2686 static const WCHAR enW[] = {'e','n',0};
2688 if (!pLocaleNameToLCID)
2690 win_skip( "LocaleNameToLCID not available\n" );
2691 return;
2694 /* special cases */
2695 buffer[0] = 0;
2696 SetLastError(0xdeadbeef);
2697 lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
2698 ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
2699 "Expected lcid == %08x, got %08x, error %d\n", GetUserDefaultLCID(), lcid, GetLastError());
2700 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2701 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2702 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2704 buffer[0] = 0;
2705 SetLastError(0xdeadbeef);
2706 lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
2707 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2708 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2709 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2710 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2711 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2713 buffer[0] = 0;
2714 SetLastError(0xdeadbeef);
2715 lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
2716 ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
2717 ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
2718 ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
2719 trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
2721 /* bad name */
2722 SetLastError(0xdeadbeef);
2723 lcid = pLocaleNameToLCID(fooW, 0);
2724 ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
2725 "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
2727 /* english neutral name */
2728 lcid = pLocaleNameToLCID(enW, 0);
2729 ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
2730 broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
2731 if (lcid)
2733 const struct neutralsublang_name_t *ptr = neutralsublang_names;
2735 while (*ptr->name)
2737 lcid = pLocaleNameToLCID(ptr->name, 0);
2738 todo_wine_if (ptr->todo)
2739 ok(lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
2740 wine_dbgstr_w(ptr->name), lcid, ptr->lcid);
2742 *buffer = 0;
2743 ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
2744 ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
2745 ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
2746 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
2748 ptr++;
2753 /* this requires collation table patch to make it MS compatible */
2754 static const char * const strings_sorted[] =
2756 "'",
2757 "-",
2758 "!",
2759 "\"",
2760 ".",
2761 ":",
2762 "\\",
2763 "_",
2764 "`",
2765 "{",
2766 "}",
2767 "+",
2768 "0",
2769 "1",
2770 "2",
2771 "3",
2772 "4",
2773 "5",
2774 "6",
2775 "7",
2776 "8",
2777 "9",
2778 "a",
2779 "A",
2780 "b",
2781 "B",
2782 "c",
2786 static const char * const strings[] =
2788 "C",
2789 "\"",
2790 "9",
2791 "'",
2792 "}",
2793 "-",
2794 "7",
2795 "+",
2796 "`",
2797 "1",
2798 "a",
2799 "5",
2800 "\\",
2801 "8",
2802 "B",
2803 "3",
2804 "_",
2805 "6",
2806 "{",
2807 "2",
2808 "c",
2809 "4",
2810 "!",
2811 "0",
2812 "A",
2813 ":",
2814 "b",
2818 static int compare_string1(const void *e1, const void *e2)
2820 const char *s1 = *(const char *const *)e1;
2821 const char *s2 = *(const char *const *)e2;
2823 return lstrcmpA(s1, s2);
2826 static int compare_string2(const void *e1, const void *e2)
2828 const char *s1 = *(const char *const *)e1;
2829 const char *s2 = *(const char *const *)e2;
2831 return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
2834 static int compare_string3(const void *e1, const void *e2)
2836 const char *s1 = *(const char *const *)e1;
2837 const char *s2 = *(const char *const *)e2;
2838 char key1[256], key2[256];
2840 LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
2841 LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
2842 return strcmp(key1, key2);
2845 static void test_sorting(void)
2847 char buf[256];
2848 char **str_buf = (char **)buf;
2849 int i;
2851 assert(sizeof(buf) >= sizeof(strings));
2853 /* 1. sort using lstrcmpA */
2854 memcpy(buf, strings, sizeof(strings));
2855 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
2856 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2858 ok(!strcmp(strings_sorted[i], str_buf[i]),
2859 "qsort using lstrcmpA failed for element %d\n", i);
2861 /* 2. sort using CompareStringA */
2862 memcpy(buf, strings, sizeof(strings));
2863 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
2864 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2866 ok(!strcmp(strings_sorted[i], str_buf[i]),
2867 "qsort using CompareStringA failed for element %d\n", i);
2869 /* 3. sort using sort keys */
2870 memcpy(buf, strings, sizeof(strings));
2871 qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
2872 for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
2874 ok(!strcmp(strings_sorted[i], str_buf[i]),
2875 "qsort using sort keys failed for element %d\n", i);
2879 static void test_FoldStringA(void)
2881 int ret, i, j;
2882 BOOL is_special;
2883 char src[256], dst[256];
2884 static const char digits_src[] = { 0xB9,0xB2,0xB3,'\0' };
2885 static const char digits_dst[] = { '1','2','3','\0' };
2886 static const char composite_src[] =
2888 0x8a,0x8e,0x9a,0x9e,0x9f,0xc0,0xc1,0xc2,
2889 0xc3,0xc4,0xc5,0xc7,0xc8,0xc9,0xca,0xcb,
2890 0xcc,0xcd,0xce,0xcf,0xd1,0xd2,0xd3,0xd4,
2891 0xd5,0xd6,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,
2892 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe7,0xe8,
2893 0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf1,
2894 0xf2,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,
2895 0xfb,0xfc,0xfd,0xff,'\0'
2897 static const char composite_dst[] =
2899 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2900 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2901 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2902 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2903 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2904 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2905 0x4f,0x7e,0x4f,0xa8,0x4f,0x3f,0x55,0x60,
2906 0x55,0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,
2907 0x61,0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,
2908 0x61,0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,
2909 0x65,0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,
2910 0x69,0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,
2911 0x6f,0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,
2912 0x6f,0xa8,0x6f,0x3f,0x75,0x60,0x75,0xb4,
2913 0x75,0x5e,0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2915 static const char composite_dst_alt[] =
2917 0x53,0x3f,0x5a,0x3f,0x73,0x3f,0x7a,0x3f,
2918 0x59,0xa8,0x41,0x60,0x41,0xb4,0x41,0x5e,
2919 0x41,0x7e,0x41,0xa8,0x41,0xb0,0x43,0xb8,
2920 0x45,0x60,0x45,0xb4,0x45,0x5e,0x45,0xa8,
2921 0x49,0x60,0x49,0xb4,0x49,0x5e,0x49,0xa8,
2922 0x4e,0x7e,0x4f,0x60,0x4f,0xb4,0x4f,0x5e,
2923 0x4f,0x7e,0x4f,0xa8,0xd8,0x55,0x60,0x55,
2924 0xb4,0x55,0x5e,0x55,0xa8,0x59,0xb4,0x61,
2925 0x60,0x61,0xb4,0x61,0x5e,0x61,0x7e,0x61,
2926 0xa8,0x61,0xb0,0x63,0xb8,0x65,0x60,0x65,
2927 0xb4,0x65,0x5e,0x65,0xa8,0x69,0x60,0x69,
2928 0xb4,0x69,0x5e,0x69,0xa8,0x6e,0x7e,0x6f,
2929 0x60,0x6f,0xb4,0x6f,0x5e,0x6f,0x7e,0x6f,
2930 0xa8,0xf8,0x75,0x60,0x75,0xb4,0x75,0x5e,
2931 0x75,0xa8,0x79,0xb4,0x79,0xa8,'\0'
2933 static const char ligatures_src[] =
2935 0x8C,0x9C,0xC6,0xDE,0xDF,0xE6,0xFE,'\0'
2937 static const char ligatures_dst[] =
2939 'O','E','o','e','A','E','T','H','s','s','a','e','t','h','\0'
2941 static const struct special
2943 char src;
2944 char dst[4];
2945 } foldczone_special[] =
2947 /* src dst */
2948 { 0x85, { 0x2e, 0x2e, 0x2e, 0x00 } },
2949 { 0x98, { 0x20, 0x7e, 0x00 } },
2950 { 0x99, { 0x54, 0x4d, 0x00 } },
2951 { 0xa0, { 0x20, 0x00 } },
2952 { 0xa8, { 0x20, 0xa8, 0x00 } },
2953 { 0xaa, { 0x61, 0x00 } },
2954 { 0xaf, { 0x20, 0xaf, 0x00 } },
2955 { 0xb2, { 0x32, 0x00 } },
2956 { 0xb3, { 0x33, 0x00 } },
2957 { 0xb4, { 0x20, 0xb4, 0x00 } },
2958 { 0xb8, { 0x20, 0xb8, 0x00 } },
2959 { 0xb9, { 0x31, 0x00 } },
2960 { 0xba, { 0x6f, 0x00 } },
2961 { 0xbc, { 0x31, 0x2f, 0x34, 0x00 } },
2962 { 0xbd, { 0x31, 0x2f, 0x32, 0x00 } },
2963 { 0xbe, { 0x33, 0x2f, 0x34, 0x00 } },
2964 { 0x00 }
2967 if (!pFoldStringA)
2968 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
2970 /* these tests are locale specific */
2971 if (GetACP() != 1252)
2973 trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
2974 return;
2977 /* MAP_FOLDDIGITS */
2978 SetLastError(0);
2979 ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
2980 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2982 win_skip("FoldStringA is not implemented\n");
2983 return;
2985 ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
2986 ok(strcmp(dst, digits_dst) == 0,
2987 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
2988 for (i = 1; i < 256; i++)
2990 if (!strchr(digits_src, i))
2992 src[0] = i;
2993 src[1] = '\0';
2994 SetLastError(0);
2995 ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256);
2996 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
2997 ok(dst[0] == src[0],
2998 "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst);
3002 /* MAP_EXPAND_LIGATURES */
3003 SetLastError(0);
3004 ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3005 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3006 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3007 ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError());
3008 ok(strcmp(dst, ligatures_dst) == 0,
3009 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst);
3010 for (i = 1; i < 256; i++)
3012 if (!strchr(ligatures_src, i))
3014 src[0] = i;
3015 src[1] = '\0';
3016 SetLastError(0);
3017 ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256);
3018 if (ret == 3)
3020 /* Vista */
3021 ok((i == 0xDC && lstrcmpA(dst, "UE") == 0) ||
3022 (i == 0xFC && lstrcmpA(dst, "ue") == 0),
3023 "Got %s for %d\n", dst, i);
3025 else
3027 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3028 ok(dst[0] == src[0],
3029 "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst);
3035 /* MAP_COMPOSITE */
3036 SetLastError(0);
3037 ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256);
3038 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3039 ok(ret == 121 || ret == 119, "Expected 121 or 119, got %d\n", ret);
3040 ok(strcmp(dst, composite_dst) == 0 || strcmp(dst, composite_dst_alt) == 0,
3041 "MAP_COMPOSITE: Mismatch, got '%s'\n", dst);
3043 for (i = 1; i < 256; i++)
3045 if (!strchr(composite_src, i))
3047 src[0] = i;
3048 src[1] = '\0';
3049 SetLastError(0);
3050 ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256);
3051 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3052 ok(dst[0] == src[0],
3053 "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0],
3054 (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]);
3058 /* MAP_FOLDCZONE */
3059 for (i = 1; i < 256; i++)
3061 src[0] = i;
3062 src[1] = '\0';
3063 SetLastError(0);
3064 ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256);
3065 is_special = FALSE;
3066 for (j = 0; foldczone_special[j].src != 0 && ! is_special; j++)
3068 if (foldczone_special[j].src == src[0])
3070 ok(ret == 2 || ret == lstrlenA(foldczone_special[j].dst) + 1,
3071 "Expected ret == 2 or %d, got %d, error %d\n",
3072 lstrlenA(foldczone_special[j].dst) + 1, ret, GetLastError());
3073 ok(src[0] == dst[0] || lstrcmpA(foldczone_special[j].dst, dst) == 0,
3074 "MAP_FOLDCZONE: string mismatch for 0x%02x\n",
3075 (unsigned char)src[0]);
3076 is_special = TRUE;
3079 if (! is_special)
3081 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3082 ok(src[0] == dst[0],
3083 "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n",
3084 (unsigned char)src[0], (unsigned char)dst[0]);
3088 /* MAP_PRECOMPOSED */
3089 for (i = 1; i < 256; i++)
3091 src[0] = i;
3092 src[1] = '\0';
3093 SetLastError(0);
3094 ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256);
3095 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3096 ok(src[0] == dst[0],
3097 "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n",
3098 (unsigned char)src[0], (unsigned char)dst[0]);
3102 static void test_FoldStringW(void)
3104 int ret;
3105 unsigned int i, j;
3106 WCHAR src[256], dst[256], ch, prev_ch = 1;
3107 static const DWORD badFlags[] =
3110 MAP_PRECOMPOSED|MAP_COMPOSITE,
3111 MAP_PRECOMPOSED|MAP_EXPAND_LIGATURES,
3112 MAP_COMPOSITE|MAP_EXPAND_LIGATURES
3114 /* Ranges of digits 0-9 : Must be sorted! */
3115 static const WCHAR digitRanges[] =
3117 0x0030, /* '0'-'9' */
3118 0x0660, /* Eastern Arabic */
3119 0x06F0, /* Arabic - Hindu */
3120 0x07C0, /* Nko */
3121 0x0966, /* Devengari */
3122 0x09E6, /* Bengalii */
3123 0x0A66, /* Gurmukhi */
3124 0x0AE6, /* Gujarati */
3125 0x0B66, /* Oriya */
3126 0x0BE6, /* Tamil - No 0 */
3127 0x0C66, /* Telugu */
3128 0x0CE6, /* Kannada */
3129 0x0D66, /* Maylayalam */
3130 0x0DE6, /* Sinhala Lith */
3131 0x0E50, /* Thai */
3132 0x0ED0, /* Laos */
3133 0x0F20, /* Tibet */
3134 0x0F29, /* Tibet half - 0 is out of sequence */
3135 0x1040, /* Myanmar */
3136 0x1090, /* Myanmar Shan */
3137 0x1368, /* Ethiopic - no 0 */
3138 0x17E0, /* Khmer */
3139 0x1810, /* Mongolian */
3140 0x1946, /* Limbu */
3141 0x19D0, /* New Tai Lue */
3142 0x1A80, /* Tai Tham Hora */
3143 0x1A90, /* Tai Tham Tham */
3144 0x1B50, /* Balinese */
3145 0x1BB0, /* Sundanese */
3146 0x1C40, /* Lepcha */
3147 0x1C50, /* Ol Chiki */
3148 0x2070, /* Superscript - 1, 2, 3 are out of sequence */
3149 0x2080, /* Subscript */
3150 0x245F, /* Circled - 0 is out of sequence */
3151 0x2473, /* Bracketed */
3152 0x2487, /* Full stop */
3153 0x24F4, /* Double Circled */
3154 0x2775, /* Inverted circled - No 0 */
3155 0x277F, /* Patterned circled - No 0 */
3156 0x2789, /* Inverted Patterned circled - No 0 */
3157 0x3020, /* Hangzhou */
3158 0xA620, /* Vai */
3159 0xA8D0, /* Saurashtra */
3160 0xA900, /* Kayah Li */
3161 0xA9D0, /* Javanese */
3162 0xA9F0, /* Myanmar Tai Laing */
3163 0xAA50, /* Cham */
3164 0xABF0, /* Meetei Mayek */
3165 0xff10, /* Pliene chasse (?) */
3166 0xffff /* Terminator */
3168 /* Digits which are represented, but out of sequence */
3169 static const WCHAR outOfSequenceDigits[] =
3171 0xB9, /* Superscript 1 */
3172 0xB2, /* Superscript 2 */
3173 0xB3, /* Superscript 3 */
3174 0x0C78, /* Telugu Fraction 0 */
3175 0x0C79, /* Telugu Fraction 1 */
3176 0x0C7A, /* Telugu Fraction 2 */
3177 0x0C7B, /* Telugu Fraction 3 */
3178 0x0C7C, /* Telugu Fraction 1 */
3179 0x0C7D, /* Telugu Fraction 2 */
3180 0x0C7E, /* Telugu Fraction 3 */
3181 0x0F33, /* Tibetan half zero */
3182 0x19DA, /* New Tai Lue Tham 1 */
3183 0x24EA, /* Circled 0 */
3184 0x24FF, /* Negative Circled 0 */
3185 0x3007, /* Ideographic number zero */
3186 '\0' /* Terminator */
3188 /* Digits in digitRanges for which no representation is available */
3189 static const WCHAR noDigitAvailable[] =
3191 0x0BE6, /* No Tamil 0 */
3192 0x0F29, /* No Tibetan half zero (out of sequence) */
3193 0x1368, /* No Ethiopic 0 */
3194 0x2473, /* No Bracketed 0 */
3195 0x2487, /* No 0 Full stop */
3196 0x24F4, /* No double circled 0 */
3197 0x2775, /* No inverted circled 0 */
3198 0x277F, /* No patterned circled */
3199 0x2789, /* No inverted Patterned circled */
3200 0x3020, /* No Hangzhou 0 */
3201 '\0' /* Terminator */
3203 static const WCHAR foldczone_src[] =
3205 'W', 'i', 'n', 'e', 0x0348, 0x0551, 0x1323, 0x280d,
3206 0xff37, 0xff49, 0xff4e, 0xff45, '\0'
3208 static const WCHAR foldczone_dst[] =
3210 'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
3212 static const WCHAR foldczone_todo_src[] =
3214 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
3216 static const WCHAR foldczone_todo_dst[] =
3218 0x3cb,0x1f0,' ','a',0
3220 static const WCHAR foldczone_todo_broken_dst[] =
3222 0x3cb,0x1f0,0xa0,0xaa,0
3224 static const WCHAR ligatures_src[] =
3226 'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
3227 0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
3228 0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
3229 0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
3230 0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
3231 0xfb04, 0xfb05, 0xfb06, '\0'
3233 static const WCHAR ligatures_dst[] =
3235 'W','i','n','e',0x03a6,0x03b9,0x03bd,0x03b5,
3236 'A','E','T','H','s','s','a','e','t','h','I','J','i','j','O','E','o','e',
3237 'D',0x017d,'D',0x017e,'d',0x017e,'L','J','L','j','l','j','N','J','N','j',
3238 'n','j',0x0100,0x0112,0x0101,0x0113,'D','Z','D','z','d','z',0x00c1,0x00c9,
3239 0x00e1,0x00e9,0x05d5,0x05d5,0x05d5,0x05d9,0x05d9,0x05d9,'f','f','f','i',
3240 'f','l','f','f','i','f','f','l',0x017f,'t','s','t','\0'
3243 if (!pFoldStringW)
3245 win_skip("FoldStringW is not available\n");
3246 return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
3249 /* Invalid flag combinations */
3250 for (i = 0; i < sizeof(badFlags)/sizeof(badFlags[0]); i++)
3252 src[0] = dst[0] = '\0';
3253 SetLastError(0);
3254 ret = pFoldStringW(badFlags[i], src, 256, dst, 256);
3255 if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
3257 win_skip("FoldStringW is not implemented\n");
3258 return;
3260 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
3261 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3264 /* src & dst cannot be the same */
3265 SetLastError(0);
3266 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256);
3267 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3268 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3270 /* src can't be NULL */
3271 SetLastError(0);
3272 ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256);
3273 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3274 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3276 /* srclen can't be 0 */
3277 SetLastError(0);
3278 ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256);
3279 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3280 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3282 /* dstlen can't be < 0 */
3283 SetLastError(0);
3284 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1);
3285 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3286 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3288 /* Ret includes terminating NUL which is appended if srclen = -1 */
3289 SetLastError(0);
3290 src[0] = 'A';
3291 src[1] = '\0';
3292 dst[0] = '\0';
3293 ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256);
3294 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3295 ok(dst[0] == 'A' && dst[1] == '\0',
3296 "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n",
3297 'A', '\0', ret, dst[0], dst[1], GetLastError());
3299 /* If size is given, result is not NUL terminated */
3300 SetLastError(0);
3301 src[0] = 'A';
3302 src[1] = 'A';
3303 dst[0] = 'X';
3304 dst[1] = 'X';
3305 ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256);
3306 ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError());
3307 ok(dst[0] == 'A' && dst[1] == 'X',
3308 "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n",
3309 'A','X', ret, dst[0], dst[1], GetLastError());
3311 /* MAP_FOLDDIGITS */
3312 for (j = 0; j < sizeof(digitRanges)/sizeof(digitRanges[0]); j++)
3314 /* Check everything before this range */
3315 for (ch = prev_ch; ch < digitRanges[j]; ch++)
3317 SetLastError(0);
3318 src[0] = ch;
3319 src[1] = dst[0] = '\0';
3320 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3321 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3323 ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
3324 (ch >= 0xa8e0 && ch <= 0xa8e9), /* combining Devanagari on Win8 */
3325 "MAP_FOLDDIGITS: ch 0x%04x Expected unchanged got %04x\n", ch, dst[0]);
3326 ok(!isdigitW(ch) || strchrW(outOfSequenceDigits, ch) ||
3327 broken( ch >= 0xbf0 && ch <= 0xbf2 ), /* win2k */
3328 "char %04x should not be a digit\n", ch );
3331 if (digitRanges[j] == 0xffff)
3332 break; /* Finished the whole code point space */
3334 for (ch = digitRanges[j]; ch < digitRanges[j] + 10; ch++)
3336 WCHAR c;
3338 /* Map out of sequence characters */
3339 if (ch == 0x2071) c = 0x00B9; /* Superscript 1 */
3340 else if (ch == 0x2072) c = 0x00B2; /* Superscript 2 */
3341 else if (ch == 0x2073) c = 0x00B3; /* Superscript 3 */
3342 else if (ch == 0x245F) c = 0x24EA; /* Circled 0 */
3343 else c = ch;
3344 SetLastError(0);
3345 src[0] = c;
3346 src[1] = dst[0] = '\0';
3347 ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256);
3348 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
3350 ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') ||
3351 broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */
3352 (digitRanges[j] == 0x3020 && dst[0] == ch) || /* Hangzhou not present in all Windows versions */
3353 (digitRanges[j] == 0x0F29 && dst[0] == ch) || /* Tibetan not present in all Windows versions */
3354 strchrW(noDigitAvailable, c),
3355 "MAP_FOLDDIGITS: ch %04x Expected %04x got %04x\n",
3356 ch, '0' + digitRanges[j] - ch, dst[0]);
3358 prev_ch = ch;
3361 /* MAP_FOLDCZONE */
3362 SetLastError(0);
3363 ret = pFoldStringW(MAP_FOLDCZONE, foldczone_src, -1, dst, 256);
3364 ok(ret == sizeof(foldczone_dst)/sizeof(foldczone_dst[0]),
3365 "Got %d, error %d\n", ret, GetLastError());
3366 ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
3367 "MAP_FOLDCZONE: Expanded incorrectly\n");
3369 ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
3370 todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
3371 "Got %d, error %d\n", ret, GetLastError());
3372 todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
3373 || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
3374 "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
3376 /* MAP_EXPAND_LIGATURES */
3377 SetLastError(0);
3378 ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
3379 /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */
3380 if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) {
3381 ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]),
3382 "Got %d, error %d\n", ret, GetLastError());
3383 ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)),
3384 "MAP_EXPAND_LIGATURES: Expanded incorrectly\n");
3387 /* FIXME: MAP_PRECOMPOSED : MAP_COMPOSITE */
3392 #define LCID_OK(l) \
3393 ok(lcid == l, "Expected lcid = %08x, got %08x\n", l, lcid)
3394 #define MKLCID(x,y,z) MAKELCID(MAKELANGID(x, y), z)
3395 #define LCID_RES(src, res) lcid = ConvertDefaultLocale(src); LCID_OK(res)
3396 #define TEST_LCIDLANG(a,b) LCID_RES(MAKELCID(a,b), MAKELCID(a,b))
3397 #define TEST_LCID(a,b,c) LCID_RES(MKLCID(a,b,c), MKLCID(a,b,c))
3399 static void test_ConvertDefaultLocale(void)
3401 LCID lcid;
3403 /* Doesn't change lcid, even if non default sublang/sort used */
3404 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_US, SORT_DEFAULT);
3405 TEST_LCID(LANG_ENGLISH, SUBLANG_ENGLISH_UK, SORT_DEFAULT);
3406 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT);
3407 TEST_LCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_JAPANESE_UNICODE);
3409 /* SUBLANG_NEUTRAL -> SUBLANG_DEFAULT */
3410 LCID_RES(MKLCID(LANG_ENGLISH, SUBLANG_NEUTRAL, SORT_DEFAULT),
3411 MKLCID(LANG_ENGLISH, SUBLANG_DEFAULT, SORT_DEFAULT));
3412 LCID_RES(MKLCID(LANG_JAPANESE, SUBLANG_NEUTRAL, SORT_DEFAULT),
3413 MKLCID(LANG_JAPANESE, SUBLANG_DEFAULT, SORT_DEFAULT));
3415 /* Invariant language is not treated specially */
3416 TEST_LCID(LANG_INVARIANT, SUBLANG_DEFAULT, SORT_DEFAULT);
3418 /* User/system default languages alone are not mapped */
3419 TEST_LCIDLANG(LANG_SYSTEM_DEFAULT, SORT_JAPANESE_UNICODE);
3420 TEST_LCIDLANG(LANG_USER_DEFAULT, SORT_JAPANESE_UNICODE);
3422 /* Default lcids */
3423 LCID_RES(LOCALE_SYSTEM_DEFAULT, GetSystemDefaultLCID());
3424 LCID_RES(LOCALE_USER_DEFAULT, GetUserDefaultLCID());
3425 LCID_RES(LOCALE_NEUTRAL, GetUserDefaultLCID());
3426 lcid = ConvertDefaultLocale(LOCALE_INVARIANT);
3427 ok(lcid == LOCALE_INVARIANT || broken(lcid == 0x47f) /* win2k[3]/winxp */,
3428 "Expected lcid = %08x, got %08x\n", LOCALE_INVARIANT, lcid);
3431 static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
3432 DWORD dwFlags, LONG_PTR lParam)
3434 if (winetest_debug > 1)
3435 trace("%08x, %s, %s, %08x, %08lx\n",
3436 lgrpid, lpszNum, lpszName, dwFlags, lParam);
3438 ok(pIsValidLanguageGroup(lgrpid, dwFlags) == TRUE,
3439 "Enumerated grp %d not valid (flags %d)\n", lgrpid, dwFlags);
3441 /* If lParam is one, we are calling with flags defaulted from 0 */
3442 ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
3443 "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %d\n", dwFlags);
3445 return TRUE;
3448 static void test_EnumSystemLanguageGroupsA(void)
3450 BOOL ret;
3452 if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup)
3454 win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n");
3455 return;
3458 /* No enumeration proc */
3459 SetLastError(0);
3460 ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0);
3461 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3463 win_skip("EnumSystemLanguageGroupsA is not implemented\n");
3464 return;
3466 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3467 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3469 /* Invalid flags */
3470 SetLastError(0);
3471 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0);
3472 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3474 /* No flags - defaults to LGRPID_INSTALLED */
3475 SetLastError(0xdeadbeef);
3476 pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1);
3477 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3479 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0);
3480 pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
3483 static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
3485 if (winetest_debug > 1)
3486 trace( "%s %x\n", wine_dbgstr_w(name), flags );
3487 return TRUE;
3490 static void test_EnumSystemLocalesEx(void)
3492 BOOL ret;
3494 if (!pEnumSystemLocalesEx)
3496 win_skip( "EnumSystemLocalesEx not available\n" );
3497 return;
3499 SetLastError( 0xdeadbeef );
3500 ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
3501 ok( !ret, "should have failed\n" );
3502 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
3503 SetLastError( 0xdeadbeef );
3504 ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
3505 ok( ret, "failed err %u\n", GetLastError() );
3508 static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
3509 LONG_PTR lParam)
3511 if (winetest_debug > 1)
3512 trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam);
3514 /* invalid locale enumerated on some platforms */
3515 if (lcid == 0)
3516 return TRUE;
3518 ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE,
3519 "Enumerated grp %d not valid\n", lgrpid);
3520 ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE,
3521 "Enumerated grp locale %04x not valid\n", lcid);
3522 return TRUE;
3525 static void test_EnumLanguageGroupLocalesA(void)
3527 BOOL ret;
3529 if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup)
3531 win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n");
3532 return;
3535 /* No enumeration proc */
3536 SetLastError(0);
3537 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0);
3538 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3540 win_skip("EnumLanguageGroupLocalesA is not implemented\n");
3541 return;
3543 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3544 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3546 /* lgrpid too small */
3547 SetLastError(0);
3548 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0);
3549 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3550 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3552 /* lgrpid too big */
3553 SetLastError(0);
3554 ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0);
3555 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3556 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3558 /* dwFlags is reserved */
3559 SetLastError(0);
3560 ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0);
3561 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
3562 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3564 pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0);
3567 static void test_SetLocaleInfoA(void)
3569 BOOL bRet;
3570 LCID lcid = GetUserDefaultLCID();
3572 /* Null data */
3573 SetLastError(0);
3574 bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0);
3575 ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER,
3576 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3578 /* IDATE */
3579 SetLastError(0);
3580 bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
3581 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3582 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3584 /* ILDATE */
3585 SetLastError(0);
3586 bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
3587 ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
3588 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3591 static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam)
3593 if (winetest_debug > 1)
3594 trace("%s %08lx\n", value, lParam);
3595 return(TRUE);
3598 static BOOL CALLBACK luilocale_proc2A(LPSTR value, LONG_PTR lParam)
3600 ok(!enumCount, "callback called again unexpected\n");
3601 enumCount++;
3602 return(FALSE);
3605 static BOOL CALLBACK luilocale_proc3A(LPSTR value, LONG_PTR lParam)
3607 ok(0,"callback called unexpected\n");
3608 return(FALSE);
3611 static void test_EnumUILanguageA(void)
3613 BOOL ret;
3614 if (!pEnumUILanguagesA) {
3615 win_skip("EnumUILanguagesA is not available on Win9x or NT4\n");
3616 return;
3619 SetLastError(ERROR_SUCCESS);
3620 ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0);
3621 if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3623 win_skip("EnumUILanguagesA is not implemented\n");
3624 return;
3626 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3628 enumCount = 0;
3629 SetLastError(ERROR_SUCCESS);
3630 ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0);
3631 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
3633 SetLastError(ERROR_SUCCESS);
3634 ret = pEnumUILanguagesA(NULL, 0, 0);
3635 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3636 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3637 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3639 SetLastError(ERROR_SUCCESS);
3640 ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0);
3641 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3642 ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
3644 SetLastError(ERROR_SUCCESS);
3645 ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0);
3646 ok(!ret, "Expected return value FALSE, got %u\n", ret);
3647 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3648 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3651 static char date_fmt_buf[1024];
3652 static WCHAR date_fmt_bufW[1024];
3654 static BOOL CALLBACK enum_datetime_procA(LPSTR fmt)
3656 lstrcatA(date_fmt_buf, fmt);
3657 lstrcatA(date_fmt_buf, "\n");
3658 return TRUE;
3661 static BOOL CALLBACK enum_datetime_procW(WCHAR *fmt)
3663 lstrcatW(date_fmt_bufW, fmt);
3664 return FALSE;
3667 static void test_EnumDateFormatsA(void)
3669 char *p, buf[256];
3670 BOOL ret;
3671 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3673 date_fmt_buf[0] = 0;
3674 SetLastError(0xdeadbeef);
3675 ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
3676 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3678 win_skip("0 for dwFlags is not supported\n");
3680 else
3682 ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
3683 trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
3684 /* test the 1st enumerated format */
3685 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3686 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3687 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3688 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3691 date_fmt_buf[0] = 0;
3692 SetLastError(0xdeadbeef);
3693 ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3694 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3696 win_skip("LOCALE_USE_CP_ACP is not supported\n");
3698 else
3700 ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3701 trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3702 /* test the 1st enumerated format */
3703 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3704 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3705 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3706 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3709 date_fmt_buf[0] = 0;
3710 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
3711 ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
3712 trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
3713 /* test the 1st enumerated format */
3714 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3715 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
3716 ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
3717 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3719 date_fmt_buf[0] = 0;
3720 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
3721 ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
3722 trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
3723 /* test the 1st enumerated format */
3724 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3725 ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
3726 ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
3727 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3729 date_fmt_buf[0] = 0;
3730 SetLastError(0xdeadbeef);
3731 ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
3732 if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
3734 win_skip("DATE_YEARMONTH is only present on W2K and later\n");
3735 return;
3737 ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
3738 trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
3739 /* test the 1st enumerated format */
3740 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3741 ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
3742 ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError());
3743 ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */,
3744 "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3747 static void test_EnumTimeFormatsA(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 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
3755 ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
3756 trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
3757 /* test the 1st enumerated format */
3758 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3759 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3760 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3761 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3763 date_fmt_buf[0] = 0;
3764 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
3765 ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3766 trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
3767 /* test the 1st enumerated format */
3768 if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
3769 ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
3770 ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3771 ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
3774 static void test_EnumTimeFormatsW(void)
3776 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
3777 WCHAR bufW[256];
3778 BOOL ret;
3780 date_fmt_bufW[0] = 0;
3781 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, 0);
3782 ok(ret, "EnumTimeFormatsW(0) error %d\n", GetLastError());
3783 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3784 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3785 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3786 wine_dbgstr_w(bufW));
3788 date_fmt_bufW[0] = 0;
3789 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, LOCALE_USE_CP_ACP);
3790 ok(ret, "EnumTimeFormatsW(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
3791 ret = GetLocaleInfoW(lcid, LOCALE_STIMEFORMAT, bufW, sizeof(bufW)/sizeof(bufW[0]));
3792 ok(ret, "GetLocaleInfoW(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
3793 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3794 wine_dbgstr_w(bufW));
3796 /* TIME_NOSECONDS is Win7+ feature */
3797 date_fmt_bufW[0] = 0;
3798 ret = EnumTimeFormatsW(enum_datetime_procW, lcid, TIME_NOSECONDS);
3799 if (!ret && GetLastError() == ERROR_INVALID_FLAGS)
3800 win_skip("EnumTimeFormatsW doesn't support TIME_NOSECONDS\n");
3801 else {
3802 char buf[256];
3804 ok(ret, "EnumTimeFormatsW(TIME_NOSECONDS) error %d\n", GetLastError());
3805 ret = GetLocaleInfoW(lcid, LOCALE_SSHORTTIME, bufW, sizeof(bufW)/sizeof(bufW[0]));
3806 ok(ret, "GetLocaleInfoW(LOCALE_SSHORTTIME) error %d\n", GetLastError());
3807 ok(!lstrcmpW(date_fmt_bufW, bufW), "expected \"%s\" got \"%s\"\n", wine_dbgstr_w(date_fmt_bufW),
3808 wine_dbgstr_w(bufW));
3810 /* EnumTimeFormatsA doesn't support this flag */
3811 ret = EnumTimeFormatsA(enum_datetime_procA, lcid, TIME_NOSECONDS);
3812 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3813 GetLastError());
3815 ret = EnumTimeFormatsA(NULL, lcid, TIME_NOSECONDS);
3816 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "EnumTimeFormatsA(TIME_NOSECONDS) ret %d, error %d\n", ret,
3817 GetLastError());
3819 /* And it's not supported by GetLocaleInfoA either */
3820 ret = GetLocaleInfoA(lcid, LOCALE_SSHORTTIME, buf, sizeof(buf)/sizeof(buf[0]));
3821 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, "GetLocaleInfoA(LOCALE_SSHORTTIME) ret %d, error %d\n", ret,
3822 GetLastError());
3825 static void test_GetCPInfo(void)
3827 BOOL ret;
3828 CPINFO cpinfo;
3830 SetLastError(0xdeadbeef);
3831 ret = GetCPInfo(CP_SYMBOL, &cpinfo);
3832 ok(!ret, "GetCPInfo(CP_SYMBOL) should fail\n");
3833 ok(GetLastError() == ERROR_INVALID_PARAMETER,
3834 "expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
3836 SetLastError(0xdeadbeef);
3837 ret = GetCPInfo(CP_UTF7, &cpinfo);
3838 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3840 win_skip("Codepage CP_UTF7 is not installed/available\n");
3842 else
3844 ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError());
3845 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3846 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3847 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3848 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3849 ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize);
3852 SetLastError(0xdeadbeef);
3853 ret = GetCPInfo(CP_UTF8, &cpinfo);
3854 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
3856 win_skip("Codepage CP_UTF8 is not installed/available\n");
3858 else
3860 ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError());
3861 ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]);
3862 ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]);
3863 ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]);
3864 ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]);
3865 ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */,
3866 "expected 4, got %u\n", cpinfo.MaxCharSize);
3871 * The CT_TYPE1 has varied over windows version.
3872 * The current target for correct behavior is windows 7.
3873 * There was a big shift between windows 2000 (first introduced) and windows Xp
3874 * Most of the old values below are from windows 2000.
3875 * A smaller subset of changes happened between windows Xp and Window vista/7
3877 static void test_GetStringTypeW(void)
3879 static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
3880 static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
3881 C1_SPACE | C1_BLANK | C1_DEFINED,
3882 C1_SPACE | C1_BLANK | C1_DEFINED,
3883 C1_SPACE | C1_BLANK | C1_DEFINED,
3884 C1_CNTRL | C1_BLANK | C1_DEFINED};
3885 static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
3886 C1_SPACE | C1_BLANK,
3887 C1_SPACE | C1_BLANK,
3888 C1_SPACE | C1_BLANK,
3889 C1_SPACE | C1_BLANK};
3891 static const WCHAR undefined[] = {0x378, 0x379, 0x5ff, 0xfff8, 0xfffe};
3893 /* Lu, Ll, Lt */
3894 static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
3895 static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
3896 C1_LOWER | C1_ALPHA,
3897 C1_UPPER | C1_LOWER | C1_ALPHA,
3898 C1_ALPHA};
3900 /* Sk, Sk, Mn, So, Me */
3901 static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
3902 /* Sc, Sm, No,*/
3903 0xffe0, 0xffe9, 0x2153};
3905 /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
3906 static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
3907 static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
3908 static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
3909 C1_ALPHA | C1_DEFINED,
3910 C1_CNTRL | C1_DEFINED,
3911 C1_PUNCT | C1_DEFINED,
3912 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3913 C1_ALPHA | C1_LOWER | C1_DEFINED,
3914 C1_ALPHA | C1_DEFINED };
3915 static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
3916 C1_ALPHA | C1_DEFINED,
3917 C1_CNTRL | C1_DEFINED,
3918 C1_PUNCT | C1_CNTRL | C1_DEFINED,
3919 C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
3920 C1_ALPHA | C1_DEFINED,
3921 C1_DEFINED
3923 /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
3924 static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
3926 static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
3927 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
3928 static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
3929 static const WCHAR lower_special[] = {0x2071, 0x207f};
3930 static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
3931 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
3932 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
3933 0xfff9, 0xfffa, 0xfffb};
3934 static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
3936 WORD types[20];
3937 WCHAR ch[2];
3938 BOOL ret;
3939 int i;
3941 /* NULL src */
3942 SetLastError(0xdeadbeef);
3943 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, NULL);
3944 ok(!ret, "got %d\n", ret);
3945 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3947 SetLastError(0xdeadbeef);
3948 ret = GetStringTypeW(CT_CTYPE1, NULL, 0, types);
3949 ok(!ret, "got %d\n", ret);
3950 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3952 SetLastError(0xdeadbeef);
3953 ret = GetStringTypeW(CT_CTYPE1, NULL, 5, types);
3954 ok(!ret, "got %d\n", ret);
3955 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
3957 memset(types,0,sizeof(types));
3958 GetStringTypeW(CT_CTYPE1, blanks, 5, types);
3959 for (i = 0; i < 5; i++)
3960 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]);
3962 memset(types,0,sizeof(types));
3963 GetStringTypeW(CT_CTYPE1, alpha, 3, types);
3964 for (i = 0; i < 3; i++)
3965 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]));
3966 memset(types,0,sizeof(types));
3967 GetStringTypeW(CT_CTYPE1, undefined, 5, types);
3968 for (i = 0; i < 5; i++)
3969 ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
3971 memset(types,0,sizeof(types));
3972 GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
3973 for (i = 0; i < 8; i++)
3974 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);
3976 memset(types,0,sizeof(types));
3977 GetStringTypeW(CT_CTYPE1, changed, 7, types);
3978 for (i = 0; i < 7; i++)
3979 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]);
3981 memset(types,0,sizeof(types));
3982 GetStringTypeW(CT_CTYPE1, punct, 7, types);
3983 for (i = 0; i < 7; i++)
3984 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));
3987 memset(types,0,sizeof(types));
3988 GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
3989 for (i = 0; i < 12; i++)
3990 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);
3992 memset(types,0,sizeof(types));
3993 GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
3994 for (i = 0; i < 3; i++)
3995 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);
3997 memset(types,0,sizeof(types));
3998 GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
3999 for (i = 0; i < 2; i++)
4000 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);
4002 memset(types,0,sizeof(types));
4003 GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
4004 for (i = 0; i < 20; i++)
4005 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);
4007 memset(types,0,sizeof(types));
4008 GetStringTypeW(CT_CTYPE1, space_special, 3, types);
4009 for (i = 0; i < 3; i++)
4010 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 );
4012 /* surrogate pairs */
4013 ch[0] = 0xd800;
4014 memset(types, 0, sizeof(types));
4015 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4016 if (types[0] == C3_NOTAPPLICABLE)
4017 win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
4018 else {
4019 ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
4021 ch[0] = 0xdc00;
4022 memset(types, 0, sizeof(types));
4023 GetStringTypeW(CT_CTYPE3, ch, 1, types);
4024 ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
4027 /* Zl, Zp categories */
4028 ch[0] = 0x2028;
4029 ch[1] = 0x2029;
4030 memset(types, 0, sizeof(types));
4031 GetStringTypeW(CT_CTYPE1, ch, 2, types);
4032 ok(types[0] == (C1_DEFINED|C1_SPACE), "got %x\n", types[0]);
4033 ok(types[1] == (C1_DEFINED|C1_SPACE), "got %x\n", types[1]);
4035 /* check Arabic range for kashida flag */
4036 for (ch[0] = 0x600; ch[0] <= 0x6ff; ch[0] += 1)
4038 types[0] = 0;
4039 ret = GetStringTypeW(CT_CTYPE3, ch, 1, types);
4040 ok(ret, "%#x: failed %d\n", ch[0], ret);
4041 if (ch[0] == 0x640) /* ARABIC TATWEEL (Kashida) */
4042 ok(types[0] & C3_KASHIDA, "%#x: type %#x\n", ch[0], types[0]);
4043 else
4044 ok(!(types[0] & C3_KASHIDA), "%#x: type %#x\n", ch[0], types[0]);
4048 static void test_IdnToNameprepUnicode(void)
4050 struct {
4051 DWORD in_len;
4052 const WCHAR in[64];
4053 DWORD ret;
4054 DWORD broken_ret;
4055 const WCHAR out[64];
4056 DWORD flags;
4057 DWORD err;
4058 DWORD todo;
4059 } test_data[] = {
4061 5, {'t','e','s','t',0},
4062 5, 5, {'t','e','s','t',0},
4063 0, 0xdeadbeef
4066 3, {'a',0xe111,'b'},
4067 0, 0, {0},
4068 0, ERROR_INVALID_NAME
4071 4, {'t',0,'e',0},
4072 0, 0, {0},
4073 0, ERROR_INVALID_NAME
4076 1, {'T',0},
4077 1, 1, {'T',0},
4078 0, 0xdeadbeef
4081 1, {0},
4082 0, 0, {0},
4083 0, ERROR_INVALID_NAME
4086 6, {' ','-','/','[',']',0},
4087 6, 6, {' ','-','/','[',']',0},
4088 0, 0xdeadbeef
4091 3, {'a','-','a'},
4092 3, 3, {'a','-','a'},
4093 IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
4096 3, {'a','a','-'},
4097 0, 0, {0},
4098 IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
4100 { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
4101 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
4102 12, 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
4103 0, 0xdeadbeef, TRUE
4106 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
4107 2, 0, {'t',0},
4108 0, 0xdeadbeef
4110 { /* Another example of incorrectly working FoldString (composition) */
4111 2, {0x3b0, 0},
4112 2, 2, {0x3b0, 0},
4113 0, 0xdeadbeef, TRUE
4116 2, {0x221, 0},
4117 0, 2, {0},
4118 0, ERROR_NO_UNICODE_TRANSLATION
4121 2, {0x221, 0},
4122 2, 2, {0x221, 0},
4123 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4126 5, {'a','.','.','a',0},
4127 0, 0, {0},
4128 0, ERROR_INVALID_NAME
4131 3, {'a','.',0},
4132 3, 3, {'a','.',0},
4133 0, 0xdeadbeef
4137 WCHAR buf[1024];
4138 DWORD i, ret, err;
4140 if (!pIdnToNameprepUnicode)
4142 win_skip("IdnToNameprepUnicode is not available\n");
4143 return;
4146 ret = pIdnToNameprepUnicode(0, test_data[0].in,
4147 test_data[0].in_len, NULL, 0);
4148 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4150 SetLastError(0xdeadbeef);
4151 ret = pIdnToNameprepUnicode(0, test_data[1].in,
4152 test_data[1].in_len, NULL, 0);
4153 err = GetLastError();
4154 ok(ret == test_data[1].ret, "ret = %d\n", ret);
4155 ok(err == test_data[1].err, "err = %d\n", err);
4157 SetLastError(0xdeadbeef);
4158 ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
4159 buf, sizeof(buf)/sizeof(WCHAR));
4160 err = GetLastError();
4161 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4162 ok(err == 0xdeadbeef, "err = %d\n", err);
4164 SetLastError(0xdeadbeef);
4165 ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
4166 buf, sizeof(buf)/sizeof(WCHAR));
4167 err = GetLastError();
4168 ok(ret == 0, "ret = %d\n", ret);
4169 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4171 SetLastError(0xdeadbeef);
4172 ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
4173 buf, sizeof(buf)/sizeof(WCHAR));
4174 err = GetLastError();
4175 ok(ret == 0, "ret = %d\n", ret);
4176 ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
4178 ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
4179 test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
4180 ok(ret == test_data[0].ret, "ret = %d\n", ret);
4182 SetLastError(0xdeadbeef);
4183 ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
4184 err = GetLastError();
4185 ok(ret == 0, "ret = %d\n", ret);
4186 ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
4188 SetLastError(0xdeadbeef);
4189 ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
4190 err = GetLastError();
4191 ok(ret == 0, "ret = %d\n", ret);
4192 ok(err == ERROR_INVALID_FLAGS || err == ERROR_INVALID_PARAMETER /* Win8 */,
4193 "err = %d\n", err);
4195 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4197 SetLastError(0xdeadbeef);
4198 ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
4199 test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
4200 err = GetLastError();
4202 todo_wine_if (test_data[i].todo)
4203 ok(ret == test_data[i].ret ||
4204 broken(ret == test_data[i].broken_ret), "%d) ret = %d\n", i, ret);
4206 if(ret != test_data[i].ret)
4207 continue;
4209 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4210 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4211 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4215 static void test_IdnToAscii(void)
4217 struct {
4218 DWORD in_len;
4219 const WCHAR in[64];
4220 DWORD ret;
4221 const WCHAR out[64];
4222 DWORD flags;
4223 DWORD err;
4224 } test_data[] = {
4226 5, {'T','e','s','t',0},
4227 5, {'T','e','s','t',0},
4228 0, 0xdeadbeef
4231 5, {'T','e',0x017c,'s','t',0},
4232 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
4233 0, 0xdeadbeef
4236 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
4237 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
4238 0, 0xdeadbeef
4241 3, {0x0105,'.',0},
4242 9, {'x','n','-','-','2','d','a','.',0},
4243 0, 0xdeadbeef
4246 10, {'h','t','t','p',':','/','/','t',0x0106,0},
4247 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
4248 0, 0xdeadbeef
4251 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
4252 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
4253 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
4254 0, 0xdeadbeef
4257 2, {0x221,0},
4258 8, {'x','n','-','-','6','l','a',0},
4259 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4263 WCHAR buf[1024];
4264 DWORD i, ret, err;
4266 if (!pIdnToAscii)
4268 win_skip("IdnToAscii is not available\n");
4269 return;
4272 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4274 SetLastError(0xdeadbeef);
4275 ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
4276 test_data[i].in_len, buf, sizeof(buf));
4277 err = GetLastError();
4278 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4279 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4280 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4281 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4285 static void test_IdnToUnicode(void)
4287 struct {
4288 DWORD in_len;
4289 const WCHAR in[64];
4290 DWORD ret;
4291 const WCHAR out[64];
4292 DWORD flags;
4293 DWORD err;
4294 } test_data[] = {
4296 5, {'T','e','s','.',0},
4297 5, {'T','e','s','.',0},
4298 0, 0xdeadbeef
4301 2, {0x105,0},
4302 0, {0},
4303 0, ERROR_INVALID_NAME
4306 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
4307 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
4308 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
4309 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
4310 0x05d1,0x05e8,0x05d9,0x05ea,0},
4311 0, 0xdeadbeef
4314 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
4315 '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
4316 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
4317 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
4318 0, 0xdeadbeef
4321 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4322 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4323 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
4324 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
4325 0, {0},
4326 0, ERROR_INVALID_NAME
4329 8, {'x','n','-','-','6','l','a',0},
4330 2, {0x221,0},
4331 IDN_ALLOW_UNASSIGNED, 0xdeadbeef
4335 WCHAR buf[1024];
4336 DWORD i, ret, err;
4338 if (!pIdnToUnicode)
4340 win_skip("IdnToUnicode is not available\n");
4341 return;
4344 for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
4346 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4347 test_data[i].in_len, NULL, 0);
4348 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4350 SetLastError(0xdeadbeef);
4351 ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
4352 test_data[i].in_len, buf, sizeof(buf));
4353 err = GetLastError();
4354 ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
4355 ok(err == test_data[i].err, "%d) err = %d\n", i, err);
4356 ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
4357 "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
4361 static void test_GetLocaleInfoEx(void)
4363 static const WCHAR enW[] = {'e','n',0};
4364 WCHAR bufferW[80], buffer2[80];
4365 INT ret;
4367 if (!pGetLocaleInfoEx)
4369 win_skip("GetLocaleInfoEx not supported\n");
4370 return;
4373 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4374 ok(ret || broken(ret == 0) /* Vista */, "got %d\n", ret);
4375 if (ret)
4377 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
4378 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
4379 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4380 static const WCHAR usaW[] = {'U','S','A',0};
4381 static const WCHAR enuW[] = {'E','N','U',0};
4382 const struct neutralsublang_name_t *ptr = neutralsublang_names;
4383 DWORD val;
4385 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4386 ok(!lstrcmpW(bufferW, enW), "got %s\n", wine_dbgstr_w(bufferW));
4388 SetLastError(0xdeadbeef);
4389 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, bufferW, 2);
4390 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, %d\n", ret, GetLastError());
4392 SetLastError(0xdeadbeef);
4393 ret = pGetLocaleInfoEx(enW, LOCALE_SNAME, NULL, 0);
4394 ok(ret == 3 && GetLastError() == 0xdeadbeef, "got %d, %d\n", ret, GetLastError());
4396 ret = pGetLocaleInfoEx(enusW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4397 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4398 ok(!lstrcmpW(bufferW, enusW), "got %s\n", wine_dbgstr_w(bufferW));
4400 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVCTRYNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4401 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4402 ok(!lstrcmpW(bufferW, usaW), "got %s\n", wine_dbgstr_w(bufferW));
4404 ret = pGetLocaleInfoEx(enW, LOCALE_SABBREVLANGNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4405 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4406 ok(!lstrcmpW(bufferW, enuW), "got %s\n", wine_dbgstr_w(bufferW));
4408 ret = pGetLocaleInfoEx(enW, LOCALE_SCOUNTRY, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4409 ok(ret == lstrlenW(bufferW)+1, "got %d\n", ret);
4410 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4411 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4413 skip("Non-English locale\n");
4415 else
4416 ok(!lstrcmpW(bufferW, statesW), "got %s\n", wine_dbgstr_w(bufferW));
4418 bufferW[0] = 0;
4419 SetLastError(0xdeadbeef);
4420 ret = pGetLocaleInfoEx(dummyW, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4421 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got %d, error %d\n", ret, GetLastError());
4423 while (*ptr->name)
4425 val = 0;
4426 pGetLocaleInfoEx(ptr->name, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
4427 todo_wine_if (ptr->todo)
4428 ok(val == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n", wine_dbgstr_w(ptr->name), val, ptr->lcid);
4429 bufferW[0] = 0;
4430 ret = pGetLocaleInfoEx(ptr->name, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4431 ok(ret == lstrlenW(bufferW)+1, "%s: got ret value %d\n", wine_dbgstr_w(ptr->name), ret);
4432 ok(!lstrcmpW(bufferW, ptr->name), "%s: got wrong LOCALE_SNAME %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
4433 ptr++;
4436 ret = pGetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, bufferW, sizeof(bufferW)/sizeof(WCHAR));
4437 ok(ret && ret == lstrlenW(bufferW)+1, "got ret value %d\n", ret);
4438 ret = GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_SNAME, buffer2, sizeof(buffer2)/sizeof(WCHAR));
4439 ok(ret && ret == lstrlenW(buffer2)+1, "got ret value %d\n", ret);
4440 ok(!lstrcmpW(bufferW, buffer2), "LOCALE_SNAMEs don't match %s %s\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(buffer2));
4444 static void test_IsValidLocaleName(void)
4446 static const WCHAR enusW[] = {'e','n','-','U','S',0};
4447 static const WCHAR zzW[] = {'z','z',0};
4448 static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
4449 BOOL ret;
4451 if (!pIsValidLocaleName)
4453 win_skip("IsValidLocaleName not supported\n");
4454 return;
4457 ret = pIsValidLocaleName(enusW);
4458 ok(ret, "IsValidLocaleName failed\n");
4459 ret = pIsValidLocaleName(zzW);
4460 ok(!ret, "IsValidLocaleName should have failed\n");
4461 ret = pIsValidLocaleName(zzzzW);
4462 ok(!ret, "IsValidLocaleName should have failed\n");
4463 ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
4464 ok(ret, "IsValidLocaleName failed\n");
4465 ret = pIsValidLocaleName(NULL);
4466 ok(!ret, "IsValidLocaleName should have failed\n");
4469 static void test_CompareStringOrdinal(void)
4471 INT ret;
4472 WCHAR test1[] = { 't','e','s','t',0 };
4473 WCHAR test2[] = { 'T','e','S','t',0 };
4474 WCHAR test3[] = { 't','e','s','t','3',0 };
4475 WCHAR null1[] = { 'a',0,'a',0 };
4476 WCHAR null2[] = { 'a',0,'b',0 };
4477 WCHAR bills1[] = { 'b','i','l','l','\'','s',0 };
4478 WCHAR bills2[] = { 'b','i','l','l','s',0 };
4479 WCHAR coop1[] = { 'c','o','-','o','p',0 };
4480 WCHAR coop2[] = { 'c','o','o','p',0 };
4481 WCHAR nonascii1[] = { 0x0102,0 };
4482 WCHAR nonascii2[] = { 0x0201,0 };
4483 WCHAR ch1, ch2;
4485 if (!pCompareStringOrdinal)
4487 win_skip("CompareStringOrdinal not supported\n");
4488 return;
4491 /* Check errors */
4492 SetLastError(0xdeadbeef);
4493 ret = pCompareStringOrdinal(NULL, 0, NULL, 0, FALSE);
4494 ok(!ret, "Got %u, expected 0\n", ret);
4495 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4496 SetLastError(0xdeadbeef);
4497 ret = pCompareStringOrdinal(test1, -1, NULL, 0, FALSE);
4498 ok(!ret, "Got %u, expected 0\n", ret);
4499 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4500 SetLastError(0xdeadbeef);
4501 ret = pCompareStringOrdinal(NULL, 0, test1, -1, FALSE);
4502 ok(!ret, "Got %u, expected 0\n", ret);
4503 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got %x, expected %x\n", GetLastError(), ERROR_INVALID_PARAMETER);
4505 /* Check case */
4506 ret = pCompareStringOrdinal(test1, -1, test1, -1, FALSE);
4507 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4508 ret = pCompareStringOrdinal(test1, -1, test2, -1, FALSE);
4509 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4510 ret = pCompareStringOrdinal(test2, -1, test1, -1, FALSE);
4511 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4512 ret = pCompareStringOrdinal(test1, -1, test2, -1, TRUE);
4513 ok(ret == CSTR_EQUAL, "Got %u, expected %u\n", ret, CSTR_EQUAL);
4515 /* Check different sizes */
4516 ret = pCompareStringOrdinal(test1, 3, test2, -1, TRUE);
4517 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4518 ret = pCompareStringOrdinal(test1, -1, test2, 3, TRUE);
4519 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4521 /* Check null character */
4522 ret = pCompareStringOrdinal(null1, 3, null2, 3, FALSE);
4523 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4524 ret = pCompareStringOrdinal(null1, 3, null2, 3, TRUE);
4525 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4526 ret = pCompareStringOrdinal(test1, 5, test3, 5, FALSE);
4527 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4528 ret = pCompareStringOrdinal(test1, 4, test1, 5, FALSE);
4529 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4531 /* Check ordinal behaviour */
4532 ret = pCompareStringOrdinal(bills1, -1, bills2, -1, FALSE);
4533 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4534 ret = pCompareStringOrdinal(coop2, -1, coop1, -1, FALSE);
4535 ok(ret == CSTR_GREATER_THAN, "Got %u, expected %u\n", ret, CSTR_GREATER_THAN);
4536 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, FALSE);
4537 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4538 ret = pCompareStringOrdinal(nonascii1, -1, nonascii2, -1, TRUE);
4539 ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
4541 for (ch1 = 0; ch1 < 512; ch1++)
4543 for (ch2 = 0; ch2 < 1024; ch2++)
4545 int diff = ch1 - ch2;
4546 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, FALSE );
4547 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4548 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4549 diff = pRtlUpcaseUnicodeChar( ch1 ) - pRtlUpcaseUnicodeChar( ch2 );
4550 ret = pCompareStringOrdinal( &ch1, 1, &ch2, 1, TRUE );
4551 ok( ret == (diff > 0 ? CSTR_GREATER_THAN : diff < 0 ? CSTR_LESS_THAN : CSTR_EQUAL),
4552 "wrong result %d %04x %04x\n", ret, ch1, ch2 );
4557 static void test_GetGeoInfo(void)
4559 char buffA[20];
4560 INT ret;
4562 if (!pGetGeoInfoA)
4564 win_skip("GetGeoInfo is not available.\n");
4565 return;
4568 /* unassigned id */
4569 SetLastError(0xdeadbeef);
4570 ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
4571 ok(ret == 0, "got %d\n", ret);
4572 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4574 ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
4575 ok(ret == 3, "got %d\n", ret);
4577 ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
4578 ok(ret == 4, "got %d\n", ret);
4580 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
4581 ok(ret == 3, "got %d\n", ret);
4582 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4584 /* buffer pointer not NULL, length is 0 - return required length */
4585 buffA[0] = 'a';
4586 SetLastError(0xdeadbeef);
4587 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
4588 ok(ret == 3, "got %d\n", ret);
4589 ok(buffA[0] == 'a', "got %c\n", buffA[0]);
4591 ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
4592 ok(ret == 4, "got %d\n", ret);
4593 ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
4595 /* shorter buffer */
4596 SetLastError(0xdeadbeef);
4597 buffA[1] = buffA[2] = 0;
4598 ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
4599 ok(ret == 0, "got %d\n", ret);
4600 ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
4601 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
4603 /* GEO_NATION returns GEOID in a string form */
4604 buffA[0] = 0;
4605 ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
4606 ok(ret == 4, "got %d\n", ret);
4607 ok(!strcmp(buffA, "203"), "got %s\n", buffA);
4609 /* GEO_PARENT */
4610 buffA[0] = 0;
4611 ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
4612 if (ret == 0)
4613 win_skip("GEO_PARENT not supported.\n");
4614 else
4616 ok(ret == 6, "got %d\n", ret);
4617 ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
4620 buffA[0] = 0;
4621 ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
4622 if (ret == 0)
4623 win_skip("GEO_ISO_UN_NUMBER not supported.\n");
4624 else
4626 ok(ret == 4, "got %d\n", ret);
4627 ok(!strcmp(buffA, "643"), "got %s\n", buffA);
4630 /* try invalid type value */
4631 SetLastError(0xdeadbeef);
4632 ret = pGetGeoInfoA(203, GEO_CURRENCYSYMBOL + 1, NULL, 0, 0);
4633 ok(ret == 0, "got %d\n", ret);
4634 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4637 static int geoidenum_count;
4638 static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
4640 INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
4641 ok(ret == 3, "got %d for %d\n", ret, geoid);
4642 /* valid geoid starts at 2 */
4643 ok(geoid >= 2, "got geoid %d\n", geoid);
4645 return geoidenum_count++ < 5;
4648 static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
4650 geoidenum_count++;
4651 return TRUE;
4654 static void test_EnumSystemGeoID(void)
4656 BOOL ret;
4658 if (!pEnumSystemGeoID)
4660 win_skip("EnumSystemGeoID is not available.\n");
4661 return;
4664 SetLastError(0xdeadbeef);
4665 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
4666 ok(!ret, "got %d\n", ret);
4667 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4669 SetLastError(0xdeadbeef);
4670 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
4671 ok(!ret, "got %d\n", ret);
4672 ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
4674 SetLastError(0xdeadbeef);
4675 ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
4676 ok(!ret, "got %d\n", ret);
4677 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
4679 ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
4680 ok(ret, "got %d\n", ret);
4682 /* only the first level is enumerated, not the whole hierarchy */
4683 geoidenum_count = 0;
4684 ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
4685 if (ret == 0)
4686 win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
4687 else
4688 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4690 geoidenum_count = 0;
4691 ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
4692 if (ret == 0)
4693 win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
4694 else
4696 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4698 geoidenum_count = 0;
4699 ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
4700 ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
4704 struct invariant_entry {
4705 const char *name;
4706 int id;
4707 const char *expect;
4710 #define X(x) #x, x
4711 static const struct invariant_entry invariant_list[] = {
4712 { X(LOCALE_ILANGUAGE), "007f" },
4713 { X(LOCALE_SENGLANGUAGE), "Invariant Language" },
4714 { X(LOCALE_SABBREVLANGNAME), "IVL" },
4715 { X(LOCALE_SNATIVELANGNAME), "Invariant Language" },
4716 { X(LOCALE_ICOUNTRY), "1" },
4717 { X(LOCALE_SENGCOUNTRY), "Invariant Country" },
4718 { X(LOCALE_SABBREVCTRYNAME), "IVC" },
4719 { X(LOCALE_SNATIVECTRYNAME), "Invariant Country" },
4720 { X(LOCALE_IDEFAULTLANGUAGE), "0409" },
4721 { X(LOCALE_IDEFAULTCOUNTRY), "1" },
4722 { X(LOCALE_IDEFAULTCODEPAGE), "437" },
4723 { X(LOCALE_IDEFAULTANSICODEPAGE), "1252" },
4724 { X(LOCALE_IDEFAULTMACCODEPAGE), "10000" },
4725 { X(LOCALE_SLIST), "," },
4726 { X(LOCALE_IMEASURE), "0" },
4727 { X(LOCALE_SDECIMAL), "." },
4728 { X(LOCALE_STHOUSAND), "," },
4729 { X(LOCALE_SGROUPING), "3;0" },
4730 { X(LOCALE_IDIGITS), "2" },
4731 { X(LOCALE_ILZERO), "1" },
4732 { X(LOCALE_INEGNUMBER), "1" },
4733 { X(LOCALE_SNATIVEDIGITS), "0123456789" },
4734 { X(LOCALE_SCURRENCY), "\x00a4" },
4735 { X(LOCALE_SINTLSYMBOL), "XDR" },
4736 { X(LOCALE_SMONDECIMALSEP), "." },
4737 { X(LOCALE_SMONTHOUSANDSEP), "," },
4738 { X(LOCALE_SMONGROUPING), "3;0" },
4739 { X(LOCALE_ICURRDIGITS), "2" },
4740 { X(LOCALE_IINTLCURRDIGITS), "2" },
4741 { X(LOCALE_ICURRENCY), "0" },
4742 { X(LOCALE_INEGCURR), "0" },
4743 { X(LOCALE_SDATE), "/" },
4744 { X(LOCALE_STIME), ":" },
4745 { X(LOCALE_SSHORTDATE), "MM/dd/yyyy" },
4746 { X(LOCALE_SLONGDATE), "dddd, dd MMMM yyyy" },
4747 { X(LOCALE_STIMEFORMAT), "HH:mm:ss" },
4748 { X(LOCALE_IDATE), "0" },
4749 { X(LOCALE_ILDATE), "1" },
4750 { X(LOCALE_ITIME), "1" },
4751 { X(LOCALE_ITIMEMARKPOSN), "0" },
4752 { X(LOCALE_ICENTURY), "1" },
4753 { X(LOCALE_ITLZERO), "1" },
4754 { X(LOCALE_IDAYLZERO), "1" },
4755 { X(LOCALE_IMONLZERO), "1" },
4756 { X(LOCALE_S1159), "AM" },
4757 { X(LOCALE_S2359), "PM" },
4758 { X(LOCALE_ICALENDARTYPE), "1" },
4759 { X(LOCALE_IOPTIONALCALENDAR), "0" },
4760 { X(LOCALE_IFIRSTDAYOFWEEK), "6" },
4761 { X(LOCALE_IFIRSTWEEKOFYEAR), "0" },
4762 { X(LOCALE_SDAYNAME1), "Monday" },
4763 { X(LOCALE_SDAYNAME2), "Tuesday" },
4764 { X(LOCALE_SDAYNAME3), "Wednesday" },
4765 { X(LOCALE_SDAYNAME4), "Thursday" },
4766 { X(LOCALE_SDAYNAME5), "Friday" },
4767 { X(LOCALE_SDAYNAME6), "Saturday" },
4768 { X(LOCALE_SDAYNAME7), "Sunday" },
4769 { X(LOCALE_SABBREVDAYNAME1), "Mon" },
4770 { X(LOCALE_SABBREVDAYNAME2), "Tue" },
4771 { X(LOCALE_SABBREVDAYNAME3), "Wed" },
4772 { X(LOCALE_SABBREVDAYNAME4), "Thu" },
4773 { X(LOCALE_SABBREVDAYNAME5), "Fri" },
4774 { X(LOCALE_SABBREVDAYNAME6), "Sat" },
4775 { X(LOCALE_SABBREVDAYNAME7), "Sun" },
4776 { X(LOCALE_SMONTHNAME1), "January" },
4777 { X(LOCALE_SMONTHNAME2), "February" },
4778 { X(LOCALE_SMONTHNAME3), "March" },
4779 { X(LOCALE_SMONTHNAME4), "April" },
4780 { X(LOCALE_SMONTHNAME5), "May" },
4781 { X(LOCALE_SMONTHNAME6), "June" },
4782 { X(LOCALE_SMONTHNAME7), "July" },
4783 { X(LOCALE_SMONTHNAME8), "August" },
4784 { X(LOCALE_SMONTHNAME9), "September" },
4785 { X(LOCALE_SMONTHNAME10), "October" },
4786 { X(LOCALE_SMONTHNAME11), "November" },
4787 { X(LOCALE_SMONTHNAME12), "December" },
4788 { X(LOCALE_SMONTHNAME13), "" },
4789 { X(LOCALE_SABBREVMONTHNAME1), "Jan" },
4790 { X(LOCALE_SABBREVMONTHNAME2), "Feb" },
4791 { X(LOCALE_SABBREVMONTHNAME3), "Mar" },
4792 { X(LOCALE_SABBREVMONTHNAME4), "Apr" },
4793 { X(LOCALE_SABBREVMONTHNAME5), "May" },
4794 { X(LOCALE_SABBREVMONTHNAME6), "Jun" },
4795 { X(LOCALE_SABBREVMONTHNAME7), "Jul" },
4796 { X(LOCALE_SABBREVMONTHNAME8), "Aug" },
4797 { X(LOCALE_SABBREVMONTHNAME9), "Sep" },
4798 { X(LOCALE_SABBREVMONTHNAME10), "Oct" },
4799 { X(LOCALE_SABBREVMONTHNAME11), "Nov" },
4800 { X(LOCALE_SABBREVMONTHNAME12), "Dec" },
4801 { X(LOCALE_SABBREVMONTHNAME13), "" },
4802 { X(LOCALE_SPOSITIVESIGN), "+" },
4803 { X(LOCALE_SNEGATIVESIGN), "-" },
4804 { X(LOCALE_IPOSSIGNPOSN), "3" },
4805 { X(LOCALE_INEGSIGNPOSN), "0" },
4806 { X(LOCALE_IPOSSYMPRECEDES), "1" },
4807 { X(LOCALE_IPOSSEPBYSPACE), "0" },
4808 { X(LOCALE_INEGSYMPRECEDES), "1" },
4809 { X(LOCALE_INEGSEPBYSPACE), "0" },
4810 { X(LOCALE_SISO639LANGNAME), "iv" },
4811 { X(LOCALE_SISO3166CTRYNAME), "IV" },
4812 { X(LOCALE_IDEFAULTEBCDICCODEPAGE), "037" },
4813 { X(LOCALE_IPAPERSIZE), "9" },
4814 { X(LOCALE_SENGCURRNAME), "International Monetary Fund" },
4815 { X(LOCALE_SNATIVECURRNAME), "International Monetary Fund" },
4816 { X(LOCALE_SYEARMONTH), "yyyy MMMM" },
4817 { X(LOCALE_IDIGITSUBSTITUTION), "1" },
4818 { X(LOCALE_SNAME), "" },
4819 { X(LOCALE_SSCRIPTS), "Latn;" },
4820 { 0 }
4822 #undef X
4824 static void test_invariant(void)
4826 int ret;
4827 int len;
4828 char buffer[BUFFER_SIZE];
4829 const struct invariant_entry *ptr = invariant_list;
4831 if (!GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer)))
4833 win_skip("GetLocaleInfoA(LOCALE_INVARIANT) not supported\n"); /* win2k */
4834 return;
4837 while (ptr->name)
4839 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|ptr->id, buffer, sizeof(buffer));
4840 if (!ret && (ptr->id == LOCALE_SNAME || ptr->id == LOCALE_SSCRIPTS))
4841 win_skip("not supported\n"); /* winxp/win2k3 */
4842 else
4844 len = strlen(ptr->expect)+1; /* include \0 */
4845 ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
4846 ptr->id, len, ret, GetLastError());
4847 ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
4848 ptr->id, ptr->expect, buffer);
4851 ptr++;
4854 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
4855 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
4857 skip("Non-English locale\n");
4859 else
4861 /* some locales translate these */
4862 static const char lang[] = "Invariant Language (Invariant Country)";
4863 static const char cntry[] = "Invariant Country";
4864 static const char sortm[] = "Math Alphanumerics";
4865 static const char sortd[] = "Default"; /* win2k3 */
4867 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SLANGUAGE, buffer, sizeof(buffer));
4868 len = lstrlenA(lang) + 1;
4869 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4870 ok(!strcmp(buffer, lang), "Expected %s, got '%s'\n", lang, buffer);
4872 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SCOUNTRY, buffer, sizeof(buffer));
4873 len = lstrlenA(cntry) + 1;
4874 ok(ret == len, "Expected ret == %d, got %d, error %d\n", len, ret, GetLastError());
4875 ok(!strcmp(buffer, cntry), "Expected %s, got '%s'\n", cntry, buffer);
4877 ret = GetLocaleInfoA(LOCALE_INVARIANT, NUO|LOCALE_SSORTNAME, buffer, sizeof(buffer));
4878 if (ret == lstrlenA(sortm)+1)
4879 ok(!strcmp(buffer, sortm), "Expected %s, got '%s'\n", sortm, buffer);
4880 else if (ret == lstrlenA(sortd)+1) /* win2k3 */
4881 ok(!strcmp(buffer, sortd), "Expected %s, got '%s'\n", sortd, buffer);
4882 else
4883 ok(0, "Expected ret == %d or %d, got %d, error %d\n",
4884 lstrlenA(sortm)+1, lstrlenA(sortd)+1, ret, GetLastError());
4888 static void test_GetSystemPreferredUILanguages(void)
4890 BOOL ret;
4891 ULONG count, size, size_id, size_name, size_buffer;
4892 WCHAR *buffer;
4895 if (!pGetSystemPreferredUILanguages)
4897 win_skip("GetSystemPreferredUILanguages is not available.\n");
4898 return;
4901 /* (in)valid first parameter */
4902 count = 0xdeadbeef;
4903 size = 0;
4904 SetLastError(0xdeadbeef);
4905 ret = pGetSystemPreferredUILanguages(0, &count, NULL, &size);
4906 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4907 ok(count, "Expected count > 0\n");
4908 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4910 count = 0xdeadbeef;
4911 size = 0;
4912 SetLastError(0xdeadbeef);
4913 ret = pGetSystemPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
4914 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4915 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4916 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4918 count = 0xdeadbeef;
4919 size = 0;
4920 SetLastError(0xdeadbeef);
4921 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
4922 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4923 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4924 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4926 count = 0xdeadbeef;
4927 size = 0;
4928 SetLastError(0xdeadbeef);
4929 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME, &count, NULL, &size);
4930 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4931 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4932 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4934 count = 0xdeadbeef;
4935 size = 0;
4936 SetLastError(0xdeadbeef);
4937 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4938 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4939 ok(count, "Expected count > 0\n");
4940 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
4942 count = 0xdeadbeef;
4943 size = 0;
4944 SetLastError(0xdeadbeef);
4945 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
4946 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4947 ok(count, "Expected count > 0\n");
4948 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
4950 /* second parameter
4951 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, NULL, NULL, &size);
4952 * -> unhandled exception c0000005
4955 /* invalid third parameter */
4956 count = 0xdeadbeef;
4957 size = 1;
4958 SetLastError(0xdeadbeef);
4959 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
4960 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
4961 ok(ERROR_INVALID_PARAMETER == GetLastError(),
4962 "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
4964 /* fourth parameter
4965 * ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, NULL);
4966 * -> unhandled exception c0000005
4969 count = 0xdeadbeef;
4970 size_id = 0;
4971 SetLastError(0xdeadbeef);
4972 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
4973 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4974 ok(count, "Expected count > 0\n");
4975 ok(size_id % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
4977 count = 0xdeadbeef;
4978 size_name = 0;
4979 SetLastError(0xdeadbeef);
4980 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
4981 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
4982 ok(count, "Expected count > 0\n");
4983 ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
4985 size_buffer = max(size_id, size_name);
4986 if(!size_buffer)
4988 skip("No valid buffer size\n");
4989 return;
4992 buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
4993 if (!buffer)
4995 skip("Failed to allocate memory for %d chars\n", size_buffer);
4996 return;
4999 count = 0xdeadbeef;
5000 size = size_buffer;
5001 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5002 SetLastError(0xdeadbeef);
5003 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5004 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5005 ok(count, "Expected count > 0\n");
5006 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5007 if (ret && size % 6 == 1)
5008 ok(!buffer[size -2] && !buffer[size -1],
5009 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5010 buffer[size -2], buffer[size -1]);
5012 count = 0xdeadbeef;
5013 size = size_buffer;
5014 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5015 SetLastError(0xdeadbeef);
5016 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5017 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5018 ok(count, "Expected count > 0\n");
5019 ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
5020 if (ret && size % 5 == 1)
5021 ok(!buffer[size -2] && !buffer[size -1],
5022 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5023 buffer[size -2], buffer[size -1]);
5025 count = 0xdeadbeef;
5026 size = size_buffer;
5027 SetLastError(0xdeadbeef);
5028 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
5029 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5030 ok(count, "Expected count > 0\n");
5031 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5032 if (ret && size % 5 == 1)
5033 ok(!buffer[size -2] && !buffer[size -1],
5034 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5035 buffer[size -2], buffer[size -1]);
5037 count = 0xdeadbeef;
5038 size = 0;
5039 SetLastError(0xdeadbeef);
5040 ret = pGetSystemPreferredUILanguages(MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
5041 ok(ret, "Expected GetSystemPreferredUILanguages to succeed\n");
5042 ok(count, "Expected count > 0\n");
5043 ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
5044 if (ret && size % 6 == 1)
5045 ok(!buffer[size -2] && !buffer[size -1],
5046 "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
5047 buffer[size -2], buffer[size -1]);
5049 count = 0xdeadbeef;
5050 size = 1;
5051 SetLastError(0xdeadbeef);
5052 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5053 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5054 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5055 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5057 count = 0xdeadbeef;
5058 size = size_id -1;
5059 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5060 SetLastError(0xdeadbeef);
5061 ret = pGetSystemPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
5062 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5063 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5064 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5066 count = 0xdeadbeef;
5067 size = size_id -2;
5068 memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
5069 SetLastError(0xdeadbeef);
5070 ret = pGetSystemPreferredUILanguages(0, &count, buffer, &size);
5071 ok(!ret, "Expected GetSystemPreferredUILanguages to fail\n");
5072 ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
5073 "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
5075 HeapFree(GetProcessHeap(), 0, buffer);
5078 static void test_GetThreadPreferredUILanguages(void)
5080 BOOL ret;
5081 ULONG count, size;
5082 WCHAR *buf;
5084 if (!pGetThreadPreferredUILanguages)
5086 win_skip("GetThreadPreferredUILanguages is not available.\n");
5087 return;
5090 size = count = 0;
5091 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, NULL, &size);
5092 ok(ret, "got %u\n", GetLastError());
5093 ok(count, "expected count > 0\n");
5094 ok(size, "expected size > 0\n");
5096 count = 0;
5097 buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size * sizeof(WCHAR));
5098 ret = pGetThreadPreferredUILanguages(MUI_LANGUAGE_ID|MUI_UI_FALLBACK, &count, buf, &size);
5099 ok(ret, "got %u\n", GetLastError());
5100 ok(count, "expected count > 0\n");
5101 HeapFree(GetProcessHeap(), 0, buf);
5104 START_TEST(locale)
5106 InitFunctionPointers();
5108 test_EnumTimeFormatsA();
5109 test_EnumTimeFormatsW();
5110 test_EnumDateFormatsA();
5111 test_GetLocaleInfoA();
5112 test_GetLocaleInfoW();
5113 test_GetLocaleInfoEx();
5114 test_GetTimeFormatA();
5115 test_GetTimeFormatEx();
5116 test_GetDateFormatA();
5117 test_GetDateFormatEx();
5118 test_GetDateFormatW();
5119 test_GetCurrencyFormatA(); /* Also tests the W version */
5120 test_GetNumberFormatA(); /* Also tests the W version */
5121 test_GetNumberFormatEx();
5122 test_CompareStringA();
5123 test_CompareStringW();
5124 test_CompareStringEx();
5125 test_LCMapStringA();
5126 test_LCMapStringW();
5127 test_LCMapStringEx();
5128 test_LocaleNameToLCID();
5129 test_FoldStringA();
5130 test_FoldStringW();
5131 test_ConvertDefaultLocale();
5132 test_EnumSystemLanguageGroupsA();
5133 test_EnumSystemLocalesEx();
5134 test_EnumLanguageGroupLocalesA();
5135 test_SetLocaleInfoA();
5136 test_EnumUILanguageA();
5137 test_GetCPInfo();
5138 test_GetStringTypeW();
5139 test_IdnToNameprepUnicode();
5140 test_IdnToAscii();
5141 test_IdnToUnicode();
5142 test_IsValidLocaleName();
5143 test_CompareStringOrdinal();
5144 test_GetGeoInfo();
5145 test_EnumSystemGeoID();
5146 test_invariant();
5147 test_GetSystemPreferredUILanguages();
5148 test_GetThreadPreferredUILanguages();
5149 /* this requires collation table patch to make it MS compatible */
5150 if (0) test_sorting();