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