Remove unnecessary executable bits
[reactos.git] / modules / rostests / winetests / kernel32 / locale.c
1 /*
2 * Unit tests for locale functions
3 *
4 * Copyright 2002 YASAR Mehmet
5 * Copyright 2003 Dmitry Timoshkov
6 * Copyright 2003 Jon Griffiths
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 * We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
24 * even when the user has overridden their default i8n settings (e.g. in
25 * the control panel i8n page), we will still get the expected results.
26 */
27
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32
33 #include "wine/test.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winnls.h"
38
39 static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
40 static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
41 static const WCHAR title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
42 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
43 static const WCHAR localeW[] = {'e','n','-','U','S',0};
44 static const WCHAR fooW[] = {'f','o','o',0};
45 static const WCHAR emptyW[] = {0};
46 static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
47
48 static inline unsigned int strlenW( const WCHAR *str )
49 {
50 const WCHAR *s = str;
51 while (*s) s++;
52 return s - str;
53 }
54
55 static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
56 {
57 if (n <= 0) return 0;
58 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
59 return *str1 - *str2;
60 }
61
62 static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
63 {
64 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
65 return NULL;
66 }
67
68 static inline BOOL isdigitW( WCHAR wc )
69 {
70 WORD type;
71 GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
72 return type & C1_DIGIT;
73 }
74
75 /* Some functions are only in later versions of kernel32.dll */
76 static WORD enumCount;
77
78 static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
79 static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
80 static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
81 static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
82 static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
83 static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
84 static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
85 static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
86 static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
87 static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
88 static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
89 static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
90 static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91 static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92 static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
93 static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
94 static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
95 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
96 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
97 LPNLSVERSIONINFO, LPVOID, LPARAM);
98 static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
99 static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
100 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
101 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
103 static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
104 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
105 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
106
107 static void InitFunctionPointers(void)
108 {
109 HMODULE mod = GetModuleHandleA("kernel32");
110
111 #define X(f) p##f = (void*)GetProcAddress(mod, #f)
112 X(GetTimeFormatEx);
113 X(GetDateFormatEx);
114 X(EnumSystemLanguageGroupsA);
115 X(EnumLanguageGroupLocalesA);
116 X(LocaleNameToLCID);
117 X(LCIDToLocaleName);
118 X(LCMapStringEx);
119 X(FoldStringA);
120 X(FoldStringW);
121 X(IsValidLanguageGroup);
122 X(EnumUILanguagesA);
123 X(EnumSystemLocalesEx);
124 X(IdnToNameprepUnicode);
125 X(IdnToAscii);
126 X(IdnToUnicode);
127 X(GetLocaleInfoEx);
128 X(IsValidLocaleName);
129 X(CompareStringOrdinal);
130 X(CompareStringEx);
131 X(GetGeoInfoA);
132 X(GetGeoInfoW);
133 X(EnumSystemGeoID);
134 X(GetSystemPreferredUILanguages);
135 X(GetThreadPreferredUILanguages);
136 X(GetUserPreferredUILanguages);
137 X(GetNumberFormatEx);
138
139 mod = GetModuleHandleA("ntdll");
140 X(RtlUpcaseUnicodeChar);
141 #undef X
142 }
143
144 #define eq(received, expected, label, type) \
145 ok((received) == (expected), "%s: got " type " instead of " type "\n", \
146 (label), (received), (expected))
147
148 #define BUFFER_SIZE 128
149 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
150
151 #define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0'
152 #define EXPECT_LENA ok(ret == lstrlenA(Expected)+1, "Expected len %d, got %d\n", lstrlenA(Expected)+1, ret)
153 #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
154 "Expected '%s', got '%s'\n", Expected, buffer)
155
156 #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
157 MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
158 SetLastError(0xdeadbeef); buffer[0] = '\0'
159 #define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret)
160 #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
161
162 #define NUO LOCALE_NOUSEROVERRIDE
163
164 static void test_GetLocaleInfoA(void)
165 {
166 int ret;
167 int len;
168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
169 char buffer[BUFFER_SIZE];
170 char expected[BUFFER_SIZE];
171 DWORD val;
172
173 ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
174
175 ret = GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (char*)&val, sizeof(val));
176 ok(ret, "got %d\n", ret);
177 ok(val == lcid, "got 0x%08x\n", val);
178
179 /* en and ar use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT
180 Same is true for zh on pre-Vista, but on Vista and higher GetLocaleInfo
181 assumes SUBLANG_NEUTRAL for zh */
182 memset(expected, 0, COUNTOF(expected));
183 len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
184 SetLastError(0xdeadbeef);
185 memset(buffer, 0, COUNTOF(buffer));
186 ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
187 ok((ret == len) && !lstrcmpA(buffer, expected),
188 "got %d with '%s' (expected %d with '%s')\n",
189 ret, buffer, len, expected);
190
191 memset(expected, 0, COUNTOF(expected));
192 len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
193 if (len) {
194 SetLastError(0xdeadbeef);
195 memset(buffer, 0, COUNTOF(buffer));
196 ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
197 ok((ret == len) && !lstrcmpA(buffer, expected),
198 "got %d with '%s' (expected %d with '%s')\n",
199 ret, buffer, len, expected);
200 }
201 else
202 win_skip("LANG_ARABIC not installed\n");
203
204 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
205 memset(expected, 0, COUNTOF(expected));
206 len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
207 SetLastError(0xdeadbeef);
208 memset(buffer, 0, COUNTOF(buffer));
209 ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
210 ok((ret == len) && !lstrcmpA(buffer, expected),
211 "got %d with '%s' (expected %d with '%s')\n",
212 ret, buffer, len, expected);
213
214
215 /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
216 * partially fill the buffer even if it is too short. See bug 637.
217 */
218 SetLastError(0xdeadbeef);
219 memset(buffer, 0, COUNTOF(buffer));
220 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
221 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
222
223 SetLastError(0xdeadbeef);
224 memset(buffer, 0, COUNTOF(buffer));
225 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
226 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
227 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
228 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
229
230 SetLastError(0xdeadbeef);
231 memset(buffer, 0, COUNTOF(buffer));
232 ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
233 ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
234 ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
235 }
236
237 struct neutralsublang_name2_t {
238 WCHAR name[3];
239 WCHAR sname[15];
240 LCID lcid;
241 LCID lcid_broken;
242 WCHAR sname_broken[15];
243 int todo;
244 };
245
246 static const struct neutralsublang_name2_t neutralsublang_names2[] = {
247 { {'a','r',0}, {'a','r','-','S','A',0},
248 MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
249 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
250 MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
251 { {'d','e',0}, {'d','e','-','D','E',0},
252 MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
253 { {'e','n',0}, {'e','n','-','U','S',0},
254 MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
255 { {'e','s',0}, {'e','s','-','E','S',0},
256 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
257 MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
258 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
259 { {'g','a',0}, {'g','a','-','I','E',0},
260 MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
261 { {'i','t',0}, {'i','t','-','I','T',0},
262 MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
263 { {'m','s',0}, {'m','s','-','M','Y',0},
264 MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
265 { {'n','l',0}, {'n','l','-','N','L',0},
266 MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
267 { {'p','t',0}, {'p','t','-','B','R',0},
268 MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
269 { {'s','r',0}, {'h','r','-','H','R',0},
270 MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_CROATIA), SORT_DEFAULT) },
271 { {'s','v',0}, {'s','v','-','S','E',0},
272 MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
273 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
274 MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
275 { {'z','h',0}, {'z','h','-','C','N',0},
276 MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
277 { {0} }
278 };
279
280 static void test_GetLocaleInfoW(void)
281 {
282 LCID lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
283 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
284 LCID lcid_en_neut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT);
285 WCHAR bufferW[80], buffer2W[80];
286 CHAR bufferA[80];
287 DWORD val;
288 DWORD ret;
289 INT i;
290
291 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
292 if (!ret) {
293 win_skip("GetLocaleInfoW() isn't implemented\n");
294 return;
295 }
296
297 ret = GetLocaleInfoW(lcid_en, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
298 ok(ret, "got %d\n", ret);
299 ok(val == lcid_en, "got 0x%08x\n", val);
300
301 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
302 if (ret)
303 {
304 static const WCHAR slangW[] = {'E','n','g','l','i','s','h',' ','(','U','n','i','t','e','d',' ',
305 'S','t','a','t','e','s',')',0};
306 static const WCHAR statesW[] = {'U','n','i','t','e','d',' ','S','t','a','t','e','s',0};
307 static const WCHAR enW[] = {'e','n','-','U','S',0};
308 const struct neutralsublang_name2_t *ptr = neutralsublang_names2;
309
310 ok(!lstrcmpW(bufferW, enW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
311
312 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SCOUNTRY, bufferW, COUNTOF(bufferW));
313 ok(ret, "got %d\n", ret);
314 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
315 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
316 {
317 skip("Non-English locale\n");
318 }
319 else
320 ok(!lstrcmpW(statesW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
321
322 ret = GetLocaleInfoW(lcid_en_neut, LOCALE_SLANGUAGE, bufferW, COUNTOF(bufferW));
323 ok(ret, "got %d\n", ret);
324 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
325 (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
326 {
327 skip("Non-English locale\n");
328 }
329 else
330 ok(!lstrcmpW(slangW, bufferW), "got wrong name %s\n", wine_dbgstr_w(bufferW));
331
332 while (*ptr->name)
333 {
334 LANGID langid;
335 LCID lcid;
336
337 /* make neutral lcid */
338 langid = MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(ptr->lcid)), SUBLANG_NEUTRAL);
339 lcid = MAKELCID(langid, SORT_DEFAULT);
340
341 val = 0;
342 GetLocaleInfoW(lcid, LOCALE_ILANGUAGE|LOCALE_RETURN_NUMBER, (WCHAR*)&val, sizeof(val)/sizeof(WCHAR));
343 todo_wine_if (ptr->todo & 0x1)
344 ok(val == ptr->lcid || (val && broken(val == ptr->lcid_broken)), "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
345 wine_dbgstr_w(ptr->name), val, ptr->lcid);
346
347 /* now check LOCALE_SNAME */
348 GetLocaleInfoW(lcid, LOCALE_SNAME, bufferW, COUNTOF(bufferW));
349 todo_wine_if (ptr->todo & 0x2)
350 ok(!lstrcmpW(bufferW, ptr->sname) ||
351 (*ptr->sname_broken && broken(!lstrcmpW(bufferW, ptr->sname_broken))),
352 "%s: got %s\n", wine_dbgstr_w(ptr->name), wine_dbgstr_w(bufferW));
353 ptr++;
354 }
355 }
356 else
357 win_skip("English neutral locale not supported\n");
358
359 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1, bufferW, COUNTOF(bufferW));
360 if (!ret) {
361 win_skip("LANG_RUSSIAN locale data unavailable\n");
362 return;
363 }
364 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
365 bufferW, COUNTOF(bufferW));
366 if (!ret) {
367 win_skip("LOCALE_RETURN_GENITIVE_NAMES isn't supported\n");
368 return;
369 }
370
371 /* LOCALE_RETURN_GENITIVE_NAMES isn't supported for GetLocaleInfoA */
372 bufferA[0] = 'a';
373 SetLastError(0xdeadbeef);
374 ret = GetLocaleInfoA(lcid_ru, LOCALE_SMONTHNAME1|LOCALE_RETURN_GENITIVE_NAMES,
375 bufferA, COUNTOF(bufferA));
376 ok(ret == 0, "LOCALE_RETURN_GENITIVE_NAMES should fail with GetLocaleInfoA\n");
377 ok(bufferA[0] == 'a', "Expected buffer to be untouched\n");
378 ok(GetLastError() == ERROR_INVALID_FLAGS,
379 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
380
381 bufferW[0] = 'a';
382 SetLastError(0xdeadbeef);
383 ret = GetLocaleInfoW(lcid_ru, LOCALE_RETURN_GENITIVE_NAMES,
384 bufferW, COUNTOF(bufferW));
385 ok(ret == 0,
386 "LOCALE_RETURN_GENITIVE_NAMES itself doesn't return anything, got %d\n", ret);
387 ok(bufferW[0] == 'a', "Expected buffer to be untouched\n");
388 ok(GetLastError() == ERROR_INVALID_FLAGS,
389 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
390
391 /* yes, test empty 13 month entry too */
392 for (i = 0; i < 12; i++) {
393 bufferW[0] = 0;
394 ret = GetLocaleInfoW(lcid_ru, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
395 bufferW, COUNTOF(bufferW));
396 ok(ret, "Expected non zero result\n");
397 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
398 ret, lstrlenW(bufferW));
399 buffer2W[0] = 0;
400 ret = GetLocaleInfoW(lcid_ru, LOCALE_SMONTHNAME1+i,
401 buffer2W, COUNTOF(buffer2W));
402 ok(ret, "Expected non zero result\n");
403 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
404 ret, lstrlenW(buffer2W));
405
406 ok(lstrcmpW(bufferW, buffer2W) != 0,
407 "Expected genitive name to differ, got the same for month %d\n", i+1);
408
409 /* for locale without genitive names nominative returned in both cases */
410 bufferW[0] = 0;
411 ret = GetLocaleInfoW(lcid_en, (LOCALE_SMONTHNAME1+i)|LOCALE_RETURN_GENITIVE_NAMES,
412 bufferW, COUNTOF(bufferW));
413 ok(ret, "Expected non zero result\n");
414 ok(ret == lstrlenW(bufferW)+1, "Expected actual length, got %d, length %d\n",
415 ret, lstrlenW(bufferW));
416 buffer2W[0] = 0;
417 ret = GetLocaleInfoW(lcid_en, LOCALE_SMONTHNAME1+i,
418 buffer2W, COUNTOF(buffer2W));
419 ok(ret, "Expected non zero result\n");
420 ok(ret == lstrlenW(buffer2W)+1, "Expected actual length, got %d, length %d\n",
421 ret, lstrlenW(buffer2W));
422
423 ok(lstrcmpW(bufferW, buffer2W) == 0,
424 "Expected same names, got different for month %d\n", i+1);
425 }
426 }
427
428 static void test_GetTimeFormatA(void)
429 {
430 int ret;
431 SYSTEMTIME curtime;
432 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
433 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
434
435 memset(&curtime, 2, sizeof(SYSTEMTIME));
436 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
437 SetLastError(0xdeadbeef);
438 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
441
442 curtime.wHour = 8;
443 curtime.wMinute = 56;
444 curtime.wSecond = 13;
445 curtime.wMilliseconds = 22;
446 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
447 SetLastError(0xdeadbeef);
448 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
450 EXPECT_LENA; EXPECT_EQA;
451
452 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
453 SetLastError(0xdeadbeef);
454 ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
455 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
456 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
457
458 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
459 SetLastError(0xdeadbeef);
460 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
461 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
462 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
463
464 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
465 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
466 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
467 EXPECT_LENA;
468
469 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
470 ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
472 EXPECT_LENA; EXPECT_EQA;
473
474 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
475 ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
476 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
477 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */
478 "Expected '', got '%s'\n", buffer );
479
480 STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
481 ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
483 EXPECT_LENA; EXPECT_EQA;
484
485 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
486 strcpy(Expected, "8:56 AM");
487 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
488 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
489 EXPECT_LENA; EXPECT_EQA;
490
491 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
492 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
493 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
494 ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */,
495 "Expected '8.@:56AM', got '%s'\n", buffer );
496
497 STRINGSA("s1s2s3", ""); /* Duplicate tokens */
498 ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
499 ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
500 ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */
501 "Expected '', got '%s'\n", buffer );
502
503 STRINGSA("t/tt", "A/AM"); /* AM time marker */
504 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
505 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
506 EXPECT_LENA; EXPECT_EQA;
507
508 curtime.wHour = 13;
509 STRINGSA("t/tt", "P/PM"); /* PM time marker */
510 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
511 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
512 EXPECT_LENA; EXPECT_EQA;
513
514 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
515 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
516 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
517 EXPECT_LENA; EXPECT_EQA;
518
519 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
520 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
521 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
522 EXPECT_LENA; EXPECT_EQA;
523
524 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
525 ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
527 EXPECT_LENA; EXPECT_EQA;
528
529 curtime.wHour = 14; /* change this to 14 or 2pm */
530 curtime.wMinute = 5;
531 curtime.wSecond = 3;
532 STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
533 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
534 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
535 EXPECT_LENA; EXPECT_EQA;
536
537 curtime.wHour = 0;
538 STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
539 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
540 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
541 EXPECT_LENA; EXPECT_EQA;
542
543 STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
544 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
545 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
546 EXPECT_LENA; EXPECT_EQA;
547
548 /* try to convert formatting strings with more than two letters
549 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
550 * NOTE: We expect any letter for which there is an upper case value
551 * we should see a replacement. For letters that DO NOT have
552 * upper case values we should see NO REPLACEMENT.
553 */
554 curtime.wHour = 8;
555 curtime.wMinute = 56;
556 curtime.wSecond = 13;
557 curtime.wMilliseconds = 22;
558 STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
559 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
560 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
561 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
562 EXPECT_LENA; EXPECT_EQA;
563
564 STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
565 strcpy(buffer, "text");
566 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
567 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
568 EXPECT_EQA;
569
570 STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
571 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
572 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
573 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
574 EXPECT_LENA; EXPECT_EQA;
575
576 STRINGSA("'''", "'"); /* invalid quoted string */
577 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
579 EXPECT_LENA; EXPECT_EQA;
580
581 /* test that msdn suggested single quotation usage works as expected */
582 STRINGSA("''''", "'"); /* single quote mark */
583 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
585 EXPECT_LENA; EXPECT_EQA;
586
587 STRINGSA("''HHHHHH", "08"); /* Normal use */
588 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
589 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
590 EXPECT_LENA; EXPECT_EQA;
591
592 /* and test for normal use of the single quotation mark */
593 STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
594 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
595 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
596 EXPECT_LENA; EXPECT_EQA;
597
598 STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
599 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
600 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
601 EXPECT_LENA; EXPECT_EQA;
602
603 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
604 ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
605 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
606 EXPECT_LENA; EXPECT_EQA;
607
608 curtime.wHour = 25;
609 STRINGSA("'123'tt", ""); /* Invalid time */
610 SetLastError(0xdeadbeef);
611 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
612 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
613 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
614
615 curtime.wHour = 12;
616 curtime.wMonth = 60; /* Invalid */
617 STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
618 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
619 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
620 EXPECT_LENA; EXPECT_EQA;
621 }
622
623 static void test_GetTimeFormatEx(void)
624 {
625 int ret;
626 SYSTEMTIME curtime;
627 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
628
629 if (!pGetTimeFormatEx)
630 {
631 win_skip("GetTimeFormatEx not supported\n");
632 return;
633 }
634
635 memset(&curtime, 2, sizeof(SYSTEMTIME));
636 STRINGSW("tt HH':'mm'@'ss", ""); /* Invalid time */
637 SetLastError(0xdeadbeef);
638 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
639 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
640 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
641
642 curtime.wHour = 8;
643 curtime.wMinute = 56;
644 curtime.wSecond = 13;
645 curtime.wMilliseconds = 22;
646 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
647 SetLastError(0xdeadbeef);
648 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
649 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
650 EXPECT_LENW; EXPECT_EQW;
651
652 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
653 SetLastError(0xdeadbeef);
654 ret = pGetTimeFormatEx(localeW, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
655 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
656 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
657
658 STRINGSW("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
659 SetLastError(0xdeadbeef);
660 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
661 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
662 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
663
664 STRINGSW("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
665 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
666 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
667 EXPECT_LENW;
668
669 STRINGSW("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
670 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
672 EXPECT_LENW; EXPECT_EQW;
673
674 STRINGSW("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
675 ret = pGetTimeFormatEx(localeW, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
676 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
677 EXPECT_LENW; EXPECT_EQW;
678
679 STRINGSW("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
680 ret = pGetTimeFormatEx(localeW, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
682 EXPECT_LENW; EXPECT_EQW;
683
684 STRINGSW("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
685 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
686 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
687 EXPECT_LENW; EXPECT_EQW;
688
689 STRINGSW("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
690 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
691 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
692 EXPECT_LENW; EXPECT_EQW;
693
694 STRINGSW("s1s2s3", ""); /* Duplicate tokens */
695 ret = pGetTimeFormatEx(localeW, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
696 ok(ret == strlenW(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
697 EXPECT_LENW; EXPECT_EQW;
698
699 STRINGSW("t/tt", "A/AM"); /* AM time marker */
700 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
701 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
702 EXPECT_LENW; EXPECT_EQW;
703
704 curtime.wHour = 13;
705 STRINGSW("t/tt", "P/PM"); /* PM time marker */
706 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
707 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
708 EXPECT_LENW; EXPECT_EQW;
709
710 STRINGSW("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
711 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
712 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
713 EXPECT_LENW; EXPECT_EQW;
714
715 STRINGSW("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
716 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
717 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
718 EXPECT_LENW; EXPECT_EQW;
719
720 STRINGSW("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
721 ret = pGetTimeFormatEx(localeW, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
722 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
723 EXPECT_LENW; EXPECT_EQW;
724
725 curtime.wHour = 14; /* change this to 14 or 2pm */
726 curtime.wMinute = 5;
727 curtime.wSecond = 3;
728 STRINGSW("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
729 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
730 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
731 EXPECT_LENW; EXPECT_EQW;
732
733 curtime.wHour = 0;
734 STRINGSW("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
735 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
736 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
737 EXPECT_LENW; EXPECT_EQW;
738
739 STRINGSW("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
740 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
741 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
742 EXPECT_LENW; EXPECT_EQW;
743
744 /* try to convert formatting strings with more than two letters
745 * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
746 * NOTE: We expect any letter for which there is an upper case value
747 * we should see a replacement. For letters that DO NOT have
748 * upper case values we should see NO REPLACEMENT.
749 */
750 curtime.wHour = 8;
751 curtime.wMinute = 56;
752 curtime.wSecond = 13;
753 curtime.wMilliseconds = 22;
754 STRINGSW("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
755 "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
756 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
757 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
758 EXPECT_LENW; EXPECT_EQW;
759
760 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
761 lstrcpyW(buffer, Expected);
762 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
763 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
764 EXPECT_EQW;
765
766 STRINGSW("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
767 "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
768 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
769 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
770 EXPECT_LENW; EXPECT_EQW;
771
772 STRINGSW("'''", "'"); /* invalid quoted string */
773 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
774 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
775 EXPECT_LENW; EXPECT_EQW;
776
777 /* test that msdn suggested single quotation usage works as expected */
778 STRINGSW("''''", "'"); /* single quote mark */
779 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
780 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
781 EXPECT_LENW; EXPECT_EQW;
782
783 STRINGSW("''HHHHHH", "08"); /* Normal use */
784 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
785 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
786 EXPECT_LENW; EXPECT_EQW;
787
788 /* and test for normal use of the single quotation mark */
789 STRINGSW("'''HHHHHH'", "'HHHHHH"); /* Normal use */
790 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
791 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
792 EXPECT_LENW; EXPECT_EQW;
793
794 STRINGSW("'''HHHHHH", "'HHHHHH"); /* Odd use */
795 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
796 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
797 EXPECT_LENW; EXPECT_EQW;
798
799 STRINGSW("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
800 ret = pGetTimeFormatEx(localeW, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
801 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
802 EXPECT_LENW; EXPECT_EQW;
803
804 curtime.wHour = 25;
805 STRINGSW("'123'tt", ""); /* Invalid time */
806 SetLastError(0xdeadbeef);
807 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
808 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
809 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
810
811 curtime.wHour = 12;
812 curtime.wMonth = 60; /* Invalid */
813 STRINGSW("h:m:s", "12:56:13"); /* Invalid date */
814 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
815 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
816 EXPECT_LENW; EXPECT_EQW;
817 }
818
819 static void test_GetDateFormatA(void)
820 {
821 int ret;
822 SYSTEMTIME curtime;
823 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
824 LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT);
825 char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
826 char Broken[BUFFER_SIZE];
827 char short_day[10], month[10], genitive_month[10];
828
829 memset(&curtime, 2, sizeof(SYSTEMTIME)); /* Invalid time */
830 STRINGSA("ddd',' MMM dd yy","");
831 SetLastError(0xdeadbeef);
832 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
833 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
834 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
835
836 curtime.wYear = 2002;
837 curtime.wMonth = 5;
838 curtime.wDay = 4;
839 curtime.wDayOfWeek = 3;
840 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */
841 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
842 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
843 EXPECT_LENA; EXPECT_EQA;
844
845 /* Same as above but with LOCALE_NOUSEROVERRIDE */
846 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
847 SetLastError(0xdeadbeef);
848 ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
849 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
850 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
851 EXPECT_EQA;
852
853 STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */
854 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
855 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
856 EXPECT_LENA; EXPECT_EQA;
857
858 curtime.wHour = 36; /* Invalid */
859 STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */
860 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
861 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
862 EXPECT_LENA; EXPECT_EQA;
863
864 STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */
865 ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0);
866 ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError());
867 EXPECT_EQA;
868
869 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
870 SetLastError(0xdeadbeef);
871 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
872 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
873 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
874
875 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
876 ret = GetDateFormatA(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer));
877 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
878 if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0)
879 ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer);
880
881 SetLastError(0xdeadbeef); buffer[0] = '\0'; /* DATE_LONGDATE */
882 ret = GetDateFormatA(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer));
883 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
884 ok(strcmp(buffer, "Saturday, May 04, 2002") == 0 ||
885 strcmp(buffer, "Saturday, May 4, 2002") == 0 /* Win 8 */,
886 "got an unexpected date string '%s'\n", buffer);
887
888 /* test for expected DATE_YEARMONTH behavior with null format */
889 /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */
890 STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */
891 SetLastError(0xdeadbeef);
892 ret = GetDateFormatA(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer));
893 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
894 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
895 EXPECT_EQA;
896
897 /* Test that using invalid DATE_* flags results in the correct error */
898 /* and return values */
899 STRINGSA("m/d/y", ""); /* Invalid flags */
900 SetLastError(0xdeadbeef);
901 ret = GetDateFormatA(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE,
902 &curtime, input, buffer, COUNTOF(buffer));
903 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
904 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
905
906 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddMMMM", buffer, COUNTOF(buffer));
907 if (!ret)
908 {
909 win_skip("LANG_RUSSIAN locale data unavailable\n");
910 return;
911 }
912
913 /* month part should be in genitive form */
914 strcpy(genitive_month, buffer + 2);
915 ret = GetDateFormatA(lcid_ru, 0, &curtime, "MMMM", buffer, COUNTOF(buffer));
916 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
917 strcpy(month, buffer);
918 ok(strcmp(genitive_month, month) != 0, "Expected different month forms\n");
919
920 ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd", buffer, COUNTOF(buffer));
921 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
922 strcpy(short_day, buffer);
923
924 STRINGSA("dd MMMMddd dd", "");
925 sprintf(Expected, "04 %s%s 04", genitive_month, short_day);
926 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
927 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
928 EXPECT_EQA;
929
930 STRINGSA("MMMMddd dd", "");
931 sprintf(Expected, "%s%s 04", month, short_day);
932 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
933 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
934 EXPECT_EQA;
935
936 STRINGSA("MMMMddd", "");
937 sprintf(Expected, "%s%s", month, short_day);
938 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
939 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
940 EXPECT_EQA;
941
942 STRINGSA("MMMMdd", "");
943 sprintf(Expected, "%s04", genitive_month);
944 sprintf(Broken, "%s04", month);
945 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
946 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
947 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
948 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
949 "Expected '%s', got '%s'\n", Expected, buffer);
950
951 STRINGSA("MMMMdd ddd", "");
952 sprintf(Expected, "%s04 %s", genitive_month, short_day);
953 sprintf(Broken, "%s04 %s", month, short_day);
954 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
955 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
956 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
957 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
958 "Expected '%s', got '%s'\n", Expected, buffer);
959
960 STRINGSA("dd dddMMMM", "");
961 sprintf(Expected, "04 %s%s", short_day, month);
962 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
963 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
964 EXPECT_EQA;
965
966 STRINGSA("dd dddMMMM ddd MMMMdd", "");
967 sprintf(Expected, "04 %s%s %s %s04", short_day, month, short_day, genitive_month);
968 sprintf(Broken, "04 %s%s %s %s04", short_day, month, short_day, month);
969 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
970 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
971 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
972 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
973 "Expected '%s', got '%s'\n", Expected, buffer);
974
975 /* with literal part */
976 STRINGSA("ddd',' MMMM dd", "");
977 sprintf(Expected, "%s, %s 04", short_day, genitive_month);
978 sprintf(Broken, "%s, %s 04", short_day, month);
979 ret = GetDateFormatA(lcid_ru, 0, &curtime, input, buffer, COUNTOF(buffer));
980 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
981 ok(strncmp(buffer, Expected, strlen(Expected)) == 0 ||
982 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
983 "Expected '%s', got '%s'\n", Expected, buffer);
984 }
985
986 static void test_GetDateFormatEx(void)
987 {
988 int ret;
989 SYSTEMTIME curtime;
990 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
991
992 if (!pGetDateFormatEx)
993 {
994 win_skip("GetDateFormatEx not supported\n");
995 return;
996 }
997
998 STRINGSW("",""); /* If flags are set, then format must be NULL */
999 SetLastError(0xdeadbeef);
1000 ret = pGetDateFormatEx(localeW, DATE_LONGDATE, NULL,
1001 input, buffer, COUNTOF(buffer), NULL);
1002 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1003 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1004 EXPECT_EQW;
1005
1006 STRINGSW("",""); /* NULL buffer, len > 0 */
1007 SetLastError(0xdeadbeef);
1008 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, COUNTOF(buffer), NULL);
1009 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1010 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1011
1012 STRINGSW("",""); /* NULL buffer, len == 0 */
1013 ret = pGetDateFormatEx(localeW, 0, NULL, input, NULL, 0, NULL);
1014 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1015 EXPECT_LENW; EXPECT_EQW;
1016
1017 STRINGSW("",""); /* Invalid flag combination */
1018 SetLastError(0xdeadbeef);
1019 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1020 input, NULL, 0, NULL);
1021 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1022 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1023 EXPECT_EQW;
1024
1025 curtime.wYear = 2002;
1026 curtime.wMonth = 10;
1027 curtime.wDay = 23;
1028 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1029 curtime.wHour = 65432; /* Invalid */
1030 curtime.wMinute = 34512; /* Invalid */
1031 curtime.wSecond = 65535; /* Invalid */
1032 curtime.wMilliseconds = 12345;
1033 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1034 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1035 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1036 EXPECT_LENW; EXPECT_EQW;
1037
1038 curtime.wYear = 2002;
1039 curtime.wMonth = 10;
1040 curtime.wDay = 23;
1041 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1042 curtime.wHour = 65432; /* Invalid */
1043 curtime.wMinute = 34512; /* Invalid */
1044 curtime.wSecond = 65535; /* Invalid */
1045 curtime.wMilliseconds = 12345;
1046 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002");
1047 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), emptyW); /* Use reserved arg */
1048 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1049 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1050
1051 /* Limit tests */
1052
1053 curtime.wYear = 1601;
1054 curtime.wMonth = 1;
1055 curtime.wDay = 1;
1056 curtime.wDayOfWeek = 0; /* Irrelevant */
1057 curtime.wHour = 0;
1058 curtime.wMinute = 0;
1059 curtime.wSecond = 0;
1060 curtime.wMilliseconds = 0;
1061 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1062 SetLastError(0xdeadbeef);
1063 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1064 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1065 EXPECT_LENW; EXPECT_EQW;
1066
1067 curtime.wYear = 1600;
1068 curtime.wMonth = 12;
1069 curtime.wDay = 31;
1070 curtime.wDayOfWeek = 0; /* Irrelevant */
1071 curtime.wHour = 23;
1072 curtime.wMinute = 59;
1073 curtime.wSecond = 59;
1074 curtime.wMilliseconds = 999;
1075 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1076 SetLastError(0xdeadbeef);
1077 ret = pGetDateFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer), NULL);
1078 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1079 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1080 }
1081
1082 static void test_GetDateFormatW(void)
1083 {
1084 int ret;
1085 SYSTEMTIME curtime;
1086 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1087 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1088
1089 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1090 ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
1091 input, buffer, COUNTOF(buffer));
1092 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1093 {
1094 win_skip("GetDateFormatW is not implemented\n");
1095 return;
1096 }
1097 ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
1098 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1099 EXPECT_EQW;
1100
1101 STRINGSW("",""); /* NULL buffer, len > 0 */
1102 SetLastError(0xdeadbeef);
1103 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer));
1104 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1105 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1106
1107 STRINGSW("",""); /* NULL buffer, len == 0 */
1108 ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0);
1109 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1110 EXPECT_LENW; EXPECT_EQW;
1111
1112 curtime.wYear = 2002;
1113 curtime.wMonth = 10;
1114 curtime.wDay = 23;
1115 curtime.wDayOfWeek = 45612; /* Should be 3 - Wednesday */
1116 curtime.wHour = 65432; /* Invalid */
1117 curtime.wMinute = 34512; /* Invalid */
1118 curtime.wSecond = 65535; /* Invalid */
1119 curtime.wMilliseconds = 12345;
1120 STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */
1121 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1122 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1123 EXPECT_LENW; EXPECT_EQW;
1124
1125 /* Limit tests */
1126
1127 curtime.wYear = 1601;
1128 curtime.wMonth = 1;
1129 curtime.wDay = 1;
1130 curtime.wDayOfWeek = 0; /* Irrelevant */
1131 curtime.wHour = 0;
1132 curtime.wMinute = 0;
1133 curtime.wSecond = 0;
1134 curtime.wMilliseconds = 0;
1135 STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601");
1136 SetLastError(0xdeadbeef);
1137 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1138 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1139 EXPECT_LENW; EXPECT_EQW;
1140
1141 curtime.wYear = 1600;
1142 curtime.wMonth = 12;
1143 curtime.wDay = 31;
1144 curtime.wDayOfWeek = 0; /* Irrelevant */
1145 curtime.wHour = 23;
1146 curtime.wMinute = 59;
1147 curtime.wSecond = 59;
1148 curtime.wMilliseconds = 999;
1149 STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600");
1150 SetLastError(0xdeadbeef);
1151 ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
1152 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1153 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1154 }
1155
1156
1157 #define CY_POS_LEFT 0
1158 #define CY_POS_RIGHT 1
1159 #define CY_POS_LEFT_SPACE 2
1160 #define CY_POS_RIGHT_SPACE 3
1161
1162 static void test_GetCurrencyFormatA(void)
1163 {
1164 static char szDot[] = { '.', '\0' };
1165 static char szComma[] = { ',', '\0' };
1166 static char szDollar[] = { '$', '\0' };
1167 int ret;
1168 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1169 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1170 CURRENCYFMTA format;
1171
1172 memset(&format, 0, sizeof(format));
1173
1174 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1175 SetLastError(0xdeadbeef);
1176 ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1177 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1178 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1179
1180 STRINGSA("23,53",""); /* Invalid character --> Error */
1181 SetLastError(0xdeadbeef);
1182 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1183 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1184 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1185
1186 STRINGSA("--",""); /* Double '-' --> Error */
1187 SetLastError(0xdeadbeef);
1188 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1189 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1190 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1191
1192 STRINGSA("0-",""); /* Trailing '-' --> Error */
1193 SetLastError(0xdeadbeef);
1194 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1195 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1196 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1197
1198 STRINGSA("0..",""); /* Double '.' --> Error */
1199 SetLastError(0xdeadbeef);
1200 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1201 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1202 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1203
1204 STRINGSA(" 0.1",""); /* Leading space --> Error */
1205 SetLastError(0xdeadbeef);
1206 ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1207 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1208 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1209
1210 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1211 SetLastError(0xdeadbeef);
1212 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2);
1213 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1214 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1215
1216 STRINGSA("2353",""); /* Format and flags given --> Error */
1217 SetLastError(0xdeadbeef);
1218 ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1219 ok( !ret, "Expected ret == 0, got %d\n", ret);
1220 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1221 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1222
1223 STRINGSA("2353",""); /* Invalid format --> Error */
1224 SetLastError(0xdeadbeef);
1225 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1226 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1227 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1228
1229 STRINGSA("2353","$2,353.00"); /* Valid number */
1230 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1231 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1232 EXPECT_LENA; EXPECT_EQA;
1233
1234 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1235 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1237 EXPECT_LENA; EXPECT_EQA;
1238
1239 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1240 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1241 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1242 EXPECT_LENA; EXPECT_EQA;
1243
1244 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1245 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1246 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1247 EXPECT_LENA; EXPECT_EQA;
1248
1249 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1250 ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1251 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1252 EXPECT_LENA; EXPECT_EQA;
1253
1254 format.NumDigits = 0; /* No decimal separator */
1255 format.LeadingZero = 0;
1256 format.Grouping = 0; /* No grouping char */
1257 format.NegativeOrder = 0;
1258 format.PositiveOrder = CY_POS_LEFT;
1259 format.lpDecimalSep = szDot;
1260 format.lpThousandSep = szComma;
1261 format.lpCurrencySymbol = szDollar;
1262
1263 STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */
1264 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1265 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1266 EXPECT_LENA; EXPECT_EQA;
1267
1268 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1269 STRINGSA("2353","$2353.0");
1270 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1271 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1272 EXPECT_LENA; EXPECT_EQA;
1273
1274 format.Grouping = 2; /* Group by 100's */
1275 STRINGSA("2353","$23,53.0");
1276 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1277 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1278 EXPECT_LENA; EXPECT_EQA;
1279
1280 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1281 format.Grouping = 3;
1282 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1283 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1284 EXPECT_LENA; EXPECT_EQA;
1285
1286 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1287 format.NegativeOrder = 2;
1288 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1289 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1290 EXPECT_LENA; EXPECT_EQA;
1291
1292 format.LeadingZero = 1; /* Always provide leading zero */
1293 STRINGSA(".5","$0.5");
1294 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1295 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1296 EXPECT_LENA; EXPECT_EQA;
1297
1298 format.PositiveOrder = CY_POS_RIGHT;
1299 STRINGSA("1","1.0$");
1300 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1301 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1302 EXPECT_LENA; EXPECT_EQA;
1303
1304 format.PositiveOrder = CY_POS_LEFT_SPACE;
1305 STRINGSA("1","$ 1.0");
1306 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1307 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1308 EXPECT_LENA; EXPECT_EQA;
1309
1310 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1311 STRINGSA("1","1.0 $");
1312 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1313 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1314 EXPECT_LENA; EXPECT_EQA;
1315
1316 format.NegativeOrder = 0;
1317 STRINGSA("-1","($1.0)");
1318 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1319 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1320 EXPECT_LENA; EXPECT_EQA;
1321
1322 format.NegativeOrder = 1;
1323 STRINGSA("-1","-$1.0");
1324 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1326 EXPECT_LENA; EXPECT_EQA;
1327
1328 format.NegativeOrder = 2;
1329 STRINGSA("-1","$-1.0");
1330 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1331 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1332 EXPECT_LENA; EXPECT_EQA;
1333
1334 format.NegativeOrder = 3;
1335 STRINGSA("-1","$1.0-");
1336 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1337 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1338 EXPECT_LENA; EXPECT_EQA;
1339
1340 format.NegativeOrder = 4;
1341 STRINGSA("-1","(1.0$)");
1342 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1343 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1344 EXPECT_LENA; EXPECT_EQA;
1345
1346 format.NegativeOrder = 5;
1347 STRINGSA("-1","-1.0$");
1348 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1349 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1350 EXPECT_LENA; EXPECT_EQA;
1351
1352 format.NegativeOrder = 6;
1353 STRINGSA("-1","1.0-$");
1354 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1355 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1356 EXPECT_LENA; EXPECT_EQA;
1357
1358 format.NegativeOrder = 7;
1359 STRINGSA("-1","1.0$-");
1360 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1361 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1362 EXPECT_LENA; EXPECT_EQA;
1363
1364 format.NegativeOrder = 8;
1365 STRINGSA("-1","-1.0 $");
1366 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1368 EXPECT_LENA; EXPECT_EQA;
1369
1370 format.NegativeOrder = 9;
1371 STRINGSA("-1","-$ 1.0");
1372 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1373 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1374 EXPECT_LENA; EXPECT_EQA;
1375
1376 format.NegativeOrder = 10;
1377 STRINGSA("-1","1.0 $-");
1378 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1379 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1380 EXPECT_LENA; EXPECT_EQA;
1381
1382 format.NegativeOrder = 11;
1383 STRINGSA("-1","$ 1.0-");
1384 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1385 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1386 EXPECT_LENA; EXPECT_EQA;
1387
1388 format.NegativeOrder = 12;
1389 STRINGSA("-1","$ -1.0");
1390 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1391 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1392 EXPECT_LENA; EXPECT_EQA;
1393
1394 format.NegativeOrder = 13;
1395 STRINGSA("-1","1.0- $");
1396 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1397 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1398 EXPECT_LENA; EXPECT_EQA;
1399
1400 format.NegativeOrder = 14;
1401 STRINGSA("-1","($ 1.0)");
1402 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1403 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1404 EXPECT_LENA; EXPECT_EQA;
1405
1406 format.NegativeOrder = 15;
1407 STRINGSA("-1","(1.0 $)");
1408 ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1409 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1410 EXPECT_LENA; EXPECT_EQA;
1411 }
1412
1413 #define NEG_PARENS 0 /* "(1.1)" */
1414 #define NEG_LEFT 1 /* "-1.1" */
1415 #define NEG_LEFT_SPACE 2 /* "- 1.1" */
1416 #define NEG_RIGHT 3 /* "1.1-" */
1417 #define NEG_RIGHT_SPACE 4 /* "1.1 -" */
1418
1419 static void test_GetNumberFormatA(void)
1420 {
1421 static char szDot[] = { '.', '\0' };
1422 static char szComma[] = { ',', '\0' };
1423 int ret;
1424 LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1425 char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE], input[BUFFER_SIZE];
1426 NUMBERFMTA format;
1427
1428 memset(&format, 0, sizeof(format));
1429
1430 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1431 SetLastError(0xdeadbeef);
1432 ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer));
1433 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1434 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1435
1436 STRINGSA("23,53",""); /* Invalid character --> Error */
1437 SetLastError(0xdeadbeef);
1438 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1439 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1441
1442 STRINGSA("--",""); /* Double '-' --> Error */
1443 SetLastError(0xdeadbeef);
1444 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1445 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1447
1448 STRINGSA("0-",""); /* Trailing '-' --> Error */
1449 SetLastError(0xdeadbeef);
1450 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1451 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1452 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1453
1454 STRINGSA("0..",""); /* Double '.' --> Error */
1455 SetLastError(0xdeadbeef);
1456 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1457 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1458 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1459
1460 STRINGSA(" 0.1",""); /* Leading space --> Error */
1461 SetLastError(0xdeadbeef);
1462 ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer));
1463 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1464 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1465
1466 STRINGSA("1234","1"); /* Length too small --> Write up to length chars */
1467 SetLastError(0xdeadbeef);
1468 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2);
1469 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1470 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1471
1472 STRINGSA("2353",""); /* Format and flags given --> Error */
1473 SetLastError(0xdeadbeef);
1474 ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer));
1475 ok( !ret, "Expected ret == 0, got %d\n", ret);
1476 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1477 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1478
1479 STRINGSA("2353",""); /* Invalid format --> Error */
1480 SetLastError(0xdeadbeef);
1481 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1482 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1483 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1484
1485 STRINGSA("2353","2,353.00"); /* Valid number */
1486 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1488 EXPECT_LENA; EXPECT_EQA;
1489
1490 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1491 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1493 EXPECT_LENA; EXPECT_EQA;
1494
1495 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1496 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1498 EXPECT_LENA; EXPECT_EQA;
1499
1500 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1501 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1503 EXPECT_LENA; EXPECT_EQA;
1504
1505 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1506 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1507 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1508 EXPECT_LENA; EXPECT_EQA;
1509
1510 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1511 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1512 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1513 EXPECT_LENA; EXPECT_EQA;
1514
1515 format.NumDigits = 0; /* No decimal separator */
1516 format.LeadingZero = 0;
1517 format.Grouping = 0; /* No grouping char */
1518 format.NegativeOrder = 0;
1519 format.lpDecimalSep = szDot;
1520 format.lpThousandSep = szComma;
1521
1522 STRINGSA("2353","2353"); /* No decimal or grouping chars expected */
1523 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1525 EXPECT_LENA; EXPECT_EQA;
1526
1527 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1528 STRINGSA("2353","2353.0");
1529 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1531 EXPECT_LENA; EXPECT_EQA;
1532
1533 format.Grouping = 2; /* Group by 100's */
1534 STRINGSA("2353","23,53.0");
1535 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1536 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1537 EXPECT_LENA; EXPECT_EQA;
1538
1539 STRINGSA("235","235.0"); /* Grouping of a positive number */
1540 format.Grouping = 3;
1541 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1543 EXPECT_LENA; EXPECT_EQA;
1544
1545 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1546 format.NegativeOrder = NEG_LEFT;
1547 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1548 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1549 EXPECT_LENA; EXPECT_EQA;
1550
1551 format.LeadingZero = 1; /* Always provide leading zero */
1552 STRINGSA(".5","0.5");
1553 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1554 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1555 EXPECT_LENA; EXPECT_EQA;
1556
1557 format.NegativeOrder = NEG_PARENS;
1558 STRINGSA("-1","(1.0)");
1559 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1561 EXPECT_LENA; EXPECT_EQA;
1562
1563 format.NegativeOrder = NEG_LEFT;
1564 STRINGSA("-1","-1.0");
1565 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1567 EXPECT_LENA; EXPECT_EQA;
1568
1569 format.NegativeOrder = NEG_LEFT_SPACE;
1570 STRINGSA("-1","- 1.0");
1571 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1573 EXPECT_LENA; EXPECT_EQA;
1574
1575 format.NegativeOrder = NEG_RIGHT;
1576 STRINGSA("-1","1.0-");
1577 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1579 EXPECT_LENA; EXPECT_EQA;
1580
1581 format.NegativeOrder = NEG_RIGHT_SPACE;
1582 STRINGSA("-1","1.0 -");
1583 ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer));
1584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1585 EXPECT_LENA; EXPECT_EQA;
1586
1587 lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1588
1589 if (IsValidLocale(lcid, 0))
1590 {
1591 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1592 Expected[3] = 160; /* Non breaking space */
1593 ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer));
1594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1595 EXPECT_LENA; EXPECT_EQA;
1596 }
1597 }
1598
1599 static void test_GetNumberFormatEx(void)
1600 {
1601 int ret;
1602 NUMBERFMTW format;
1603 static WCHAR dotW[] = {'.',0};
1604 static WCHAR commaW[] = {',',0};
1605 static const WCHAR enW[] = {'e','n','-','U','S',0};
1606 static const WCHAR frW[] = {'f','r','-','F','R',0};
1607 static const WCHAR bogusW[] = {'b','o','g','u','s',0};
1608 WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
1609
1610 if (!pGetNumberFormatEx)
1611 {
1612 win_skip("GetNumberFormatEx is not available.\n");
1613 return;
1614 }
1615
1616 STRINGSW("23",""); /* NULL output, length > 0 --> Error */
1617 ret = pGetNumberFormatEx(enW, 0, input, NULL, NULL, COUNTOF(buffer));
1618 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1619 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1620
1621 STRINGSW("23,53",""); /* Invalid character --> Error */
1622 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1623 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1624 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1625
1626 STRINGSW("--",""); /* Double '-' --> Error */
1627 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1628 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1629 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1630
1631 STRINGSW("0-",""); /* Trailing '-' --> Error */
1632 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1633 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1634 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1635
1636 STRINGSW("0..",""); /* Double '.' --> Error */
1637 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1638 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1639 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1640
1641 STRINGSW(" 0.1",""); /* Leading space --> Error */
1642 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
1643 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1644 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1645
1646 STRINGSW("1234","1"); /* Length too small --> Write up to length chars */
1647 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, 2);
1648 ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
1649 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1650
1651 STRINGSW("23",""); /* Bogus locale --> Error */
1652 ret = pGetNumberFormatEx(bogusW, NUO, input, NULL, buffer, COUNTOF(buffer));
1653 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1654 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1655
1656 memset(&format, 0, sizeof(format));
1657
1658 STRINGSW("2353",""); /* Format and flags given --> Error */
1659 ret = pGetNumberFormatEx(enW, NUO, input, &format, buffer, COUNTOF(buffer));
1660 ok( !ret, "Expected ret == 0, got %d\n", ret);
1661 ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER,
1662 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1663
1664 STRINGSW("2353",""); /* Invalid format --> Error */
1665 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1666 ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER,
1667 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1668
1669 STRINGSW("2353","2,353.00"); /* Valid number */
1670 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1671 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1672 EXPECT_LENW; EXPECT_EQW;
1673
1674 STRINGSW("-2353","-2,353.00"); /* Valid negative number */
1675 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1676 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1677 EXPECT_LENW; EXPECT_EQW;
1678
1679 STRINGSW("-353","-353.00"); /* test for off by one error in grouping */
1680 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1681 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1682 EXPECT_LENW; EXPECT_EQW;
1683
1684 STRINGSW("2353.1","2,353.10"); /* Valid real number */
1685 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1686 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1687 EXPECT_LENW; EXPECT_EQW;
1688
1689 STRINGSW("2353.111","2,353.11"); /* Too many DP --> Truncated */
1690 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1691 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1692 EXPECT_LENW; EXPECT_EQW;
1693
1694 STRINGSW("2353.119","2,353.12"); /* Too many DP --> Rounded */
1695 ret = pGetNumberFormatEx(enW, NUO, input, NULL, buffer, COUNTOF(buffer));
1696 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1697 EXPECT_LENW; EXPECT_EQW;
1698
1699 format.NumDigits = 0; /* No decimal separator */
1700 format.LeadingZero = 0;
1701 format.Grouping = 0; /* No grouping char */
1702 format.NegativeOrder = 0;
1703 format.lpDecimalSep = dotW;
1704 format.lpThousandSep = commaW;
1705
1706 STRINGSW("2353","2353"); /* No decimal or grouping chars expected */
1707 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1708 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1709 EXPECT_LENW; EXPECT_EQW;
1710
1711 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1712 STRINGSW("2353","2353.0");
1713 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1714 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1715 EXPECT_LENW; EXPECT_EQW;
1716
1717 format.Grouping = 2; /* Group by 100's */
1718 STRINGSW("2353","23,53.0");
1719 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1720 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1721 EXPECT_LENW; EXPECT_EQW;
1722
1723 STRINGSW("235","235.0"); /* Grouping of a positive number */
1724 format.Grouping = 3;
1725 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1726 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1727 EXPECT_LENW; EXPECT_EQW;
1728
1729 STRINGSW("-235","-235.0"); /* Grouping of a negative number */
1730 format.NegativeOrder = NEG_LEFT;
1731 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1732 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1733 EXPECT_LENW; EXPECT_EQW;
1734
1735 format.LeadingZero = 1; /* Always provide leading zero */
1736 STRINGSW(".5","0.5");
1737 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1738 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1739 EXPECT_LENW; EXPECT_EQW;
1740
1741 format.NegativeOrder = NEG_PARENS;
1742 STRINGSW("-1","(1.0)");
1743 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1744 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1745 EXPECT_LENW; EXPECT_EQW;
1746
1747 format.NegativeOrder = NEG_LEFT;
1748 STRINGSW("-1","-1.0");
1749 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1750 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1751 EXPECT_LENW; EXPECT_EQW;
1752
1753 format.NegativeOrder = NEG_LEFT_SPACE;
1754 STRINGSW("-1","- 1.0");
1755 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1756 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1757 EXPECT_LENW; EXPECT_EQW;
1758
1759 format.NegativeOrder = NEG_RIGHT;
1760 STRINGSW("-1","1.0-");
1761 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1762 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1763 EXPECT_LENW; EXPECT_EQW;
1764
1765 format.NegativeOrder = NEG_RIGHT_SPACE;
1766 STRINGSW("-1","1.0 -");
1767 ret = pGetNumberFormatEx(enW, 0, input, &format, buffer, COUNTOF(buffer));
1768 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1769 EXPECT_LENW; EXPECT_EQW;
1770
1771 if (pIsValidLocaleName(frW))
1772 {
1773 STRINGSW("-12345","-12 345,00"); /* Try French formatting */
1774 Expected[3] = 160; /* Non breaking space */
1775 ret = pGetNumberFormatEx(frW, NUO, input, NULL, buffer, COUNTOF(buffer));
1776 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1777 EXPECT_LENW; EXPECT_EQW;
1778 }
1779 }
1780
1781 struct comparestringa_entry {
1782 LCID lcid;
1783 DWORD flags;
1784 const char *first;
1785 int first_len;
1786 const char *second;
1787 int second_len;
1788 int ret;
1789 };
1790
1791 static const struct comparestringa_entry comparestringa_data[] = {
1792 { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
1793 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
1794 { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
1795 { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
1796 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
1797 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
1798 { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1799 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
1800 { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
1801 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
1802 { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
1803 { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
1804 { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
1805 { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
1806 { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
1807 { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
1808 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
1809 { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
1810 { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
1811 /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
1812 { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
1813 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
1814 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
1815 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
1816 { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
1817 { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
1818 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
1819 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
1820 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
1821 { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN },
1822 { LOCALE_SYSTEM_DEFAULT, 0, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1823 { LOCALE_SYSTEM_DEFAULT, 0, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1824 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a-", 3, "a\0", 3, CSTR_GREATER_THAN },
1825 { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "a'", 3, "a\0", 3, CSTR_GREATER_THAN },
1826 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a.", 3, "a\0", 3, CSTR_EQUAL },
1827 { LOCALE_SYSTEM_DEFAULT, NORM_IGNORESYMBOLS, "a ", 3, "a\0", 3, CSTR_EQUAL },
1828 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0\0", 4, CSTR_EQUAL },
1829 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0\0", 4, CSTR_EQUAL },
1830 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 1, CSTR_EQUAL },
1831 { LOCALE_SYSTEM_DEFAULT, 0, "a\0\0", 4, "a", 2, CSTR_EQUAL },
1832 { LOCALE_SYSTEM_DEFAULT, 0, "a", 1, "a\0x", 4, CSTR_LESS_THAN },
1833 { LOCALE_SYSTEM_DEFAULT, 0, "a", 2, "a\0x", 4, CSTR_LESS_THAN },
1834 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 1, CSTR_GREATER_THAN },
1835 { LOCALE_SYSTEM_DEFAULT, 0, "a\0x", 4, "a", 2, CSTR_GREATER_THAN },
1836 };
1837
1838 static void test_CompareStringA(void)
1839 {
1840 int ret, i;
1841 char a[256];
1842 LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
1843
1844 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1845 {
1846 const struct comparestringa_entry *entry = &comparestringa_data[i];
1847
1848 ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
1849 entry->second, entry->second_len);
1850 ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
1851 }
1852
1853 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
1854 ok (ret == CSTR_LESS_THAN, "(Salut/Salute) Expected CSTR_LESS_THAN, got %d\n", ret);
1855
1856 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "SaLuT", -1);
1857 ok (ret == CSTR_EQUAL, "(Salut/SaLuT) Expected CSTR_EQUAL, got %d\n", ret);
1858
1859 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "hola", -1);
1860 ok (ret == CSTR_GREATER_THAN, "(Salut/hola) Expected CSTR_GREATER_THAN, got %d\n", ret);
1861
1862 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1863 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1864
1865 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
1866
1867 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", -1);
1868 ok (ret == CSTR_LESS_THAN, "(haha/hoho) Expected CSTR_LESS_THAN, got %d\n", ret);
1869
1870 ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
1871 ok (ret == CSTR_GREATER_THAN, "(haha/hoho) Expected CSTR_GREATER_THAN, got %d\n", ret);
1872
1873 ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
1874 ok (ret == CSTR_EQUAL, "(Salut/saLuT) Expected CSTR_EQUAL, got %d\n", ret);
1875
1876 /* test for CompareStringA flags */
1877 SetLastError(0xdeadbeef);
1878 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1);
1879 ok(GetLastError() == ERROR_INVALID_FLAGS,
1880 "unexpected error code %d\n", GetLastError());
1881 ok(!ret, "CompareStringA must fail with invalid flag\n");
1882
1883 SetLastError(0xdeadbeef);
1884 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, LOCALE_USE_CP_ACP, "NULL", -1, "NULL", -1);
1885 ok(GetLastError() == 0xdeadbeef, "unexpected error code %d\n", GetLastError());
1886 ok(ret == CSTR_EQUAL, "CompareStringA error: %d != CSTR_EQUAL\n", ret);
1887 /* end of test for CompareStringA flags */
1888
1889 ret = lstrcmpA("", "");
1890 ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret);
1891
1892 ret = lstrcmpA(NULL, NULL);
1893 ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret);
1894
1895 ret = lstrcmpA("", NULL);
1896 ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret);
1897
1898 ret = lstrcmpA(NULL, "");
1899 ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
1900
1901
1902 if (0) { /* this requires collation table patch to make it MS compatible */
1903 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
1904 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1905
1906 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
1907 ok(ret == CSTR_LESS_THAN, "'o vs -o expected CSTR_LESS_THAN, got %d\n", ret);
1908
1909 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
1910 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1911
1912 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
1913 ok(ret == CSTR_LESS_THAN, "' vs - expected CSTR_LESS_THAN, got %d\n", ret);
1914
1915 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
1916 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1917
1918 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
1919 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1920
1921 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
1922 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1923
1924 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
1925 ok(ret == CSTR_LESS_THAN, "/m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1926
1927 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
1928 ok(ret == CSTR_LESS_THAN, "`o vs -m expected CSTR_LESS_THAN, got %d\n", ret);
1929
1930 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
1931 ok(ret == CSTR_GREATER_THAN, "-m vs `o CSTR_GREATER_THAN got %d\n", ret);
1932
1933 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
1934 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1935
1936 ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
1937 ok(ret == CSTR_LESS_THAN, "-m vs `o expected CSTR_LESS_THAN, got %d\n", ret);
1938 }
1939
1940
1941 /* WinXP handles embedded NULLs differently than earlier versions */
1942 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
1943 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLuZkUtZ vs aLuZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1944
1945 ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
1946 ok(ret == CSTR_LESS_THAN || ret == CSTR_EQUAL, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected CSTR_LESS_THAN or CSTR_EQUAL, got %d\n", ret);
1947
1948 ret = CompareStringA(lcid, 0, "a\0b", -1, "a", -1);
1949 ok(ret == CSTR_EQUAL, "a vs a expected CSTR_EQUAL, got %d\n", ret);
1950
1951 ret = CompareStringA(lcid, 0, "a\0b", 4, "a", 2);
1952 ok(ret == CSTR_EQUAL || /* win2k */
1953 ret == CSTR_GREATER_THAN,
1954 "a\\0b vs a expected CSTR_EQUAL or CSTR_GREATER_THAN, got %d\n", ret);
1955
1956 ret = CompareStringA(lcid, 0, "\2", 2, "\1", 2);
1957 todo_wine ok(ret != CSTR_EQUAL, "\\2 vs \\1 expected unequal\n");
1958
1959 ret = CompareStringA(lcid, NORM_IGNORECASE | LOCALE_USE_CP_ACP, "#", -1, ".", -1);
1960 ok(ret == CSTR_LESS_THAN, "\"#\" vs \".\" expected CSTR_LESS_THAN, got %d\n", ret);
1961
1962 ret = CompareStringA(lcid, NORM_IGNORECASE, "_", -1, ".", -1);
1963 ok(ret == CSTR_GREATER_THAN, "\"_\" vs \".\" expected CSTR_GREATER_THAN, got %d\n", ret);
1964
1965 ret = lstrcmpiA("#", ".");
1966 ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
1967
1968 lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
1969
1970 /* \xB9 character lies between a and b */
1971 ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
1972 todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
1973 ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
1974 ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
1975
1976 memset(a, 'a', sizeof(a));
1977 SetLastError(0xdeadbeef);
1978 ret = CompareStringA(lcid, 0, a, sizeof(a), a, sizeof(a));
1979 ok (GetLastError() == 0xdeadbeef && ret == CSTR_EQUAL,
1980 "ret %d, error %d, expected value %d\n", ret, GetLastError(), CSTR_EQUAL);
1981 }
1982
1983 static void test_CompareStringW(void)
1984 {
1985 WCHAR *str1, *str2;
1986 SYSTEM_INFO si;
1987 DWORD old_prot;
1988 BOOL success;
1989 char *buf;
1990 int ret;
1991
1992 GetSystemInfo(&si);
1993 buf = VirtualAlloc(NULL, si.dwPageSize * 4, MEM_COMMIT, PAGE_READWRITE);
1994 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
1995 success = VirtualProtect(buf + si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1996 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1997 success = VirtualProtect(buf + 3 * si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &old_prot);
1998 ok(success, "VirtualProtect failed with %u\n", GetLastError());
1999
2000 str1 = (WCHAR *)(buf + si.dwPageSize - sizeof(WCHAR));
2001 str2 = (WCHAR *)(buf + 3 * si.dwPageSize - sizeof(WCHAR));
2002 *str1 = 'A';
2003 *str2 = 'B';
2004
2005 /* CompareStringW should abort on the first non-matching character */
2006 ret = CompareStringW(CP_ACP, 0, str1, 100, str2, 100);
2007 ok(ret == CSTR_LESS_THAN, "expected CSTR_LESS_THAN, got %d\n", ret);
2008
2009 success = VirtualFree(buf, 0, MEM_RELEASE);
2010 ok(success, "VirtualFree failed with %u\n", GetLastError());
2011 }
2012
2013 struct comparestringex_test {
2014 const char *locale;
2015 DWORD flags;
2016 const WCHAR first[2];
2017 const WCHAR second[2];
2018 INT ret;
2019 INT broken;
2020 BOOL todo;
2021 };
2022
2023 static const struct comparestringex_test comparestringex_tests[] = {
2024 /* default behavior */
2025 { /* 0 */
2026 "tr-TR", 0,
2027 {'i',0}, {'I',0}, CSTR_LESS_THAN, -1, FALSE
2028 },
2029 { /* 1 */
2030 "tr-TR", 0,
2031 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2032 },
2033 { /* 2 */
2034 "tr-TR", 0,
2035 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2036 },
2037 { /* 3 */
2038 "tr-TR", 0,
2039 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2040 },
2041 { /* 4 */
2042 "tr-TR", 0,
2043 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2044 },
2045 { /* 5 */
2046 "tr-TR", 0,
2047 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2048 },
2049 /* with NORM_IGNORECASE */
2050 { /* 6 */
2051 "tr-TR", NORM_IGNORECASE,
2052 {'i',0}, {'I',0}, CSTR_EQUAL, -1, FALSE
2053 },
2054 { /* 7 */
2055 "tr-TR", NORM_IGNORECASE,
2056 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2057 },
2058 { /* 8 */
2059 "tr-TR", NORM_IGNORECASE,
2060 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2061 },
2062 { /* 9 */
2063 "tr-TR", NORM_IGNORECASE,
2064 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2065 },
2066 { /* 10 */
2067 "tr-TR", NORM_IGNORECASE,
2068 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2069 },
2070 { /* 11 */
2071 "tr-TR", NORM_IGNORECASE,
2072 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2073 },
2074 /* with NORM_LINGUISTIC_CASING */
2075 { /* 12 */
2076 "tr-TR", NORM_LINGUISTIC_CASING,
2077 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2078 },
2079 { /* 13 */
2080 "tr-TR", NORM_LINGUISTIC_CASING,
2081 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2082 },
2083 { /* 14 */
2084 "tr-TR", NORM_LINGUISTIC_CASING,
2085 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2086 },
2087 { /* 15 */
2088 "tr-TR", NORM_LINGUISTIC_CASING,
2089 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2090 },
2091 { /* 16 */
2092 "tr-TR", NORM_LINGUISTIC_CASING,
2093 {'I',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2094 },
2095 { /* 17 */
2096 "tr-TR", NORM_LINGUISTIC_CASING,
2097 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2098 },
2099 /* with LINGUISTIC_IGNORECASE */
2100 { /* 18 */
2101 "tr-TR", LINGUISTIC_IGNORECASE,
2102 {'i',0}, {'I',0}, CSTR_EQUAL, -1, TRUE
2103 },
2104 { /* 19 */
2105 "tr-TR", LINGUISTIC_IGNORECASE,
2106 {'i',0}, {0x130,0}, CSTR_LESS_THAN, -1, FALSE
2107 },
2108 { /* 20 */
2109 "tr-TR", LINGUISTIC_IGNORECASE,
2110 {'i',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2111 },
2112 { /* 21 */
2113 "tr-TR", LINGUISTIC_IGNORECASE,
2114 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2115 },
2116 { /* 22 */
2117 "tr-TR", LINGUISTIC_IGNORECASE,
2118 {'I',0}, {0x131,0}, CSTR_LESS_THAN, -1, FALSE
2119 },
2120 { /* 23 */
2121 "tr-TR", LINGUISTIC_IGNORECASE,
2122 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2123 },
2124 /* with NORM_LINGUISTIC_CASING | NORM_IGNORECASE */
2125 { /* 24 */
2126 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2127 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2128 },
2129 { /* 25 */
2130 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2131 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2132 },
2133 { /* 26 */
2134 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2135 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2136 },
2137 { /* 27 */
2138 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2139 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2140 },
2141 { /* 28 */
2142 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2143 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2144 },
2145 { /* 29 */
2146 "tr-TR", NORM_LINGUISTIC_CASING | NORM_IGNORECASE,
2147 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2148 },
2149 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2150 { /* 30 */
2151 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2152 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2153 },
2154 { /* 31 */
2155 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2156 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2157 },
2158 { /* 32 */
2159 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2160 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2161 },
2162 { /* 33 */
2163 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2164 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2165 },
2166 { /* 34 */
2167 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2168 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2169 },
2170 { /* 35 */
2171 "tr-TR", NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE,
2172 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2173 }
2174 };
2175
2176 static void test_CompareStringEx(void)
2177 {
2178 const char *op[] = {"ERROR", "CSTR_LESS_THAN", "CSTR_EQUAL", "CSTR_GREATER_THAN"};
2179 WCHAR locale[6];
2180 INT ret, i;
2181
2182 /* CompareStringEx is only available on Vista+ */
2183 if (!pCompareStringEx)
2184 {
2185 win_skip("CompareStringEx not supported\n");
2186 return;
2187 }
2188
2189 for (i = 0; i < sizeof(comparestringex_tests)/sizeof(comparestringex_tests[0]); i++)
2190 {
2191 const struct comparestringex_test *e = &comparestringex_tests[i];
2192
2193 MultiByteToWideChar(CP_ACP, 0, e->locale, -1, locale, sizeof(locale)/sizeof(WCHAR));
2194 ret = pCompareStringEx(locale, e->flags, e->first, -1, e->second, -1, NULL, NULL, 0);
2195 todo_wine_if (e->todo)
2196 ok(ret == e->ret || broken(ret == e->broken),
2197 "%d: got %s, expected %s\n", i, op[ret], op[e->ret]);
2198 }
2199
2200 }
2201
2202 static const DWORD lcmap_invalid_flags[] = {
2203 0,
2204 LCMAP_HIRAGANA | LCMAP_KATAKANA,
2205 LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
2206 LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
2207 LCMAP_LOWERCASE | SORT_STRINGSORT,
2208 LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
2209 LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
2210 LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
2211 LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
2212 LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
2213 LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
2214 LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
2215 LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
2216 LCMAP_KATAKANA | NORM_IGNORENONSPACE,
2217 LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
2218 LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
2219 LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
2220 LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
2221 LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
2222 LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2223 LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
2224 LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
2225 LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
2226 LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
2227 LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
2228 };
2229
2230 static void test_LCMapStringA(void)
2231 {
2232 int ret, ret2, i;
2233 char buf[256], buf2[256];
2234 static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
2235 static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
2236 static const char symbols_stripped[] = "justateststring1";
2237
2238 SetLastError(0xdeadbeef);
2239 ret = LCMapStringA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP | LCMAP_LOWERCASE,
2240 lower_case, -1, buf, sizeof(buf));
2241 ok(ret == lstrlenA(lower_case) + 1,
2242 "ret %d, error %d, expected value %d\n",
2243 ret, GetLastError(), lstrlenA(lower_case) + 1);
2244 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2245
2246 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
2247 upper_case, -1, buf, sizeof(buf));
2248 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
2249 ok(GetLastError() == ERROR_INVALID_FLAGS,
2250 "unexpected error code %d\n", GetLastError());
2251
2252 /* test invalid flag combinations */
2253 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2254 lstrcpyA(buf, "foo");
2255 SetLastError(0xdeadbeef);
2256 ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
2257 lower_case, -1, buf, sizeof(buf));
2258 ok(GetLastError() == ERROR_INVALID_FLAGS,
2259 "LCMapStringA (flag %08x) unexpected error code %d\n",
2260 lcmap_invalid_flags[i], GetLastError());
2261 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2262 lcmap_invalid_flags[i], ret);
2263 }
2264
2265 /* test LCMAP_LOWERCASE */
2266 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2267 upper_case, -1, buf, sizeof(buf));
2268 ok(ret == lstrlenA(upper_case) + 1,
2269 "ret %d, error %d, expected value %d\n",
2270 ret, GetLastError(), lstrlenA(upper_case) + 1);
2271 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2272
2273 /* test LCMAP_UPPERCASE */
2274 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2275 lower_case, -1, buf, sizeof(buf));
2276 ok(ret == lstrlenA(lower_case) + 1,
2277 "ret %d, error %d, expected value %d\n",
2278 ret, GetLastError(), lstrlenA(lower_case) + 1);
2279 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2280
2281 /* test buffer overflow */
2282 SetLastError(0xdeadbeef);
2283 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2284 lower_case, -1, buf, 4);
2285 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
2286 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2287
2288 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2289 lstrcpyA(buf, lower_case);
2290 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
2291 buf, -1, buf, sizeof(buf));
2292 if (!ret) /* Win9x */
2293 trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
2294 else
2295 {
2296 ok(ret == lstrlenA(lower_case) + 1,
2297 "ret %d, error %d, expected value %d\n",
2298 ret, GetLastError(), lstrlenA(lower_case) + 1);
2299 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2300 }
2301 lstrcpyA(buf, upper_case);
2302 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
2303 buf, -1, buf, sizeof(buf));
2304 if (!ret) /* Win9x */
2305 trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
2306 else
2307 {
2308 ok(ret == lstrlenA(upper_case) + 1,
2309 "ret %d, error %d, expected value %d\n",
2310 ret, GetLastError(), lstrlenA(lower_case) + 1);
2311 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2312 }
2313
2314 /* otherwise src == dst should fail */
2315 SetLastError(0xdeadbeef);
2316 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
2317 buf, 10, buf, sizeof(buf));
2318 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2319 GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
2320 "unexpected error code %d\n", GetLastError());
2321 ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
2322
2323 /* test whether '\0' is always appended */
2324 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2325 upper_case, -1, buf, sizeof(buf));
2326 ok(ret, "LCMapStringA must succeed\n");
2327 ok(buf[ret-1] == 0, "LCMapStringA not null-terminated\n");
2328 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2329 upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
2330 ok(ret2, "LCMapStringA must succeed\n");
2331 ok(buf2[ret2-1] == 0, "LCMapStringA not null-terminated\n" );
2332 ok(ret == ret2, "lengths of sort keys must be equal\n");
2333 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2334
2335 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2336 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
2337 upper_case, -1, buf, sizeof(buf));
2338 ok(ret, "LCMapStringA must succeed\n");
2339 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2340 lower_case, -1, buf2, sizeof(buf2));
2341 ok(ret2, "LCMapStringA must succeed\n");
2342 ok(ret == ret2, "lengths of sort keys must be equal\n");
2343 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2344
2345 /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2346 results from plain LCMAP_SORTKEY on Vista */
2347
2348 /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2349 ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORESYMBOLS,
2350 lower_case, -1, buf, sizeof(buf));
2351 ok(ret, "LCMapStringA must succeed\n");
2352 ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
2353 symbols_stripped, -1, buf2, sizeof(buf2));
2354 ok(ret2, "LCMapStringA must succeed\n");
2355 ok(ret == ret2, "lengths of sort keys must be equal\n");
2356 ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
2357
2358 /* test NORM_IGNORENONSPACE */
2359 lstrcpyA(buf, "foo");
2360 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
2361 lower_case, -1, buf, sizeof(buf));
2362 ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
2363 lstrlenA(lower_case) + 1, ret);
2364 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2365
2366 /* test NORM_IGNORESYMBOLS */
2367 lstrcpyA(buf, "foo");
2368 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
2369 lower_case, -1, buf, sizeof(buf));
2370 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2371 lstrlenA(symbols_stripped) + 1, ret);
2372 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2373
2374 /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2375 lstrcpyA(buf, "foo");
2376 ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
2377 lower_case, -1, buf, sizeof(buf));
2378 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
2379 lstrlenA(symbols_stripped) + 1, ret);
2380 ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2381
2382 /* test srclen = 0 */
2383 SetLastError(0xdeadbeef);
2384 ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
2385 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2386 ok(GetLastError() == ERROR_INVALID_PARAMETER,
2387 "unexpected error code %d\n", GetLastError());
2388 }
2389
2390 typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
2391
2392 static void test_lcmapstring_unicode(lcmapstring_wr