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