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