ReactOS 0.4.16-dev-88-ga65b6ae
locale.c
Go to the documentation of this file.
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
39static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
40static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
41static const WCHAR title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
42static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
43static const WCHAR localeW[] = {'e','n','-','U','S',0};
44static const WCHAR fooW[] = {'f','o','o',0};
45static const WCHAR emptyW[] = {0};
46static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
47
48static inline unsigned int strlenW( const WCHAR *str )
49{
50 const WCHAR *s = str;
51 while (*s) s++;
52 return s - str;
53}
54
55static 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
62static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
63{
64 do { if (*str == ch) return (WCHAR *)str; } while (*str++);
65 return NULL;
66}
67
68static 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 */
77
78static INT (WINAPI *pGetTimeFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT);
79static INT (WINAPI *pGetDateFormatEx)(LPCWSTR, DWORD, const SYSTEMTIME *, LPCWSTR, LPWSTR, INT, LPCWSTR);
80static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROCA, DWORD, LONG_PTR);
81static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA, LGRPID, DWORD, LONG_PTR);
82static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
83static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
85static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
86static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
87static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
88static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
89static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
90static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
91static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
92static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
93static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT);
94static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
95static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
96static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
98static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
99static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
100static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
101static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
102static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
103static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
104static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
105static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
106
107static void InitFunctionPointers(void)
108{
109 HMODULE mod = GetModuleHandleA("kernel32");
110
111#define X(f) p##f = (void*)GetProcAddress(mod, #f)
116 X(LocaleNameToLCID);
117 X(LCIDToLocaleName);
119 X(FoldStringA);
120 X(FoldStringW);
125 X(IdnToAscii);
127 X(GetLocaleInfoEx);
129 X(CompareStringOrdinal);
131 X(GetGeoInfoA);
132 X(GetGeoInfoW);
137 X(GetNumberFormatEx);
138
139 mod = GetModuleHandleA("ntdll");
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
164static void test_GetLocaleInfoA(void)
165{
166 int ret;
167 int len;
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 */
184 SetLastError(0xdeadbeef);
187 ok((ret == len) && !lstrcmpA(buffer, expected),
188 "got %d with '%s' (expected %d with '%s')\n",
190
193 if (len) {
194 SetLastError(0xdeadbeef);
197 ok((ret == len) && !lstrcmpA(buffer, expected),
198 "got %d with '%s' (expected %d with '%s')\n",
200 }
201 else
202 win_skip("LANG_ARABIC not installed\n");
203
204 /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
207 SetLastError(0xdeadbeef);
210 ok((ret == len) && !lstrcmpA(buffer, expected),
211 "got %d with '%s' (expected %d with '%s')\n",
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);
221 ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
222
223 SetLastError(0xdeadbeef);
227 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
228 ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
229
230 SetLastError(0xdeadbeef);
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
243 int todo;
244};
245
247 { {'a','r',0}, {'a','r','-','S','A',0},
249 { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0},
251 { {'d','e',0}, {'d','e','-','D','E',0},
253 { {'e','n',0}, {'e','n','-','U','S',0},
255 { {'e','s',0}, {'e','s','-','E','S',0},
258 {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
259 { {'g','a',0}, {'g','a','-','I','E',0},
261 { {'i','t',0}, {'i','t','-','I','T',0},
263 { {'m','s',0}, {'m','s','-','M','Y',0},
265 { {'n','l',0}, {'n','l','-','N','L',0},
267 { {'p','t',0}, {'p','t','-','B','R',0},
269 { {'s','r',0}, {'h','r','-','H','R',0},
271 { {'s','v',0}, {'s','v','-','S','E',0},
273 { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
275 { {'z','h',0}, {'z','h','-','C','N',0},
277 { {0} }
278};
279
280static void test_GetLocaleInfoW(void)
281{
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};
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);
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);
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 {
335 LCID lcid;
336
337 /* make neutral lcid */
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 }
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);
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");
379 "Expected ERROR_INVALID_FLAGS, got %x\n", GetLastError());
380
381 bufferW[0] = 'a';
382 SetLastError(0xdeadbeef);
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");
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;
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;
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;
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;
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
428static void test_GetTimeFormatA(void)
429{
430 int ret;
431 SYSTEMTIME curtime;
434
435 memset(&curtime, 2, sizeof(SYSTEMTIME));
436 STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
437 SetLastError(0xdeadbeef);
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);
449 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
451
452 /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */
453 SetLastError(0xdeadbeef);
456 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
457
458 STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */
459 SetLastError(0xdeadbeef);
462 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
463
464 STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
466 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
468
469 STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
471 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
473
474 STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
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 */
482 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
484
485 STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
486 strcpy(Expected, "8:56 AM");
488 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
490
491 STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
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 */
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());
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());
513
514 STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
516 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
518
519 STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
521 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
523
524 STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
526 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
602
603 STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
605 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
607
608 curtime.wHour = 25;
609 STRINGSA("'123'tt", ""); /* Invalid time */
610 SetLastError(0xdeadbeef);
611 ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
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());
621}
622
623static void test_GetTimeFormatEx(void)
624{
625 int ret;
626 SYSTEMTIME curtime;
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));
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());
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));
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);
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
759
760 STRINGSW("h", "text"); /* Don't write to buffer if len is 0 */
762 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, 0);
763 ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError());
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());
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());
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());
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());
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());
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());
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());
803
804 curtime.wHour = 25;
805 STRINGSW("'123'tt", ""); /* Invalid time */
806 SetLastError(0xdeadbeef);
807 ret = pGetTimeFormatEx(localeW, 0, &curtime, input, buffer, COUNTOF(buffer));
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());
817}
818
819static void test_GetDateFormatA(void)
820{
821 int ret;
822 SYSTEMTIME curtime;
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));
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());
844
845 /* Same as above but with LOCALE_NOUSEROVERRIDE */
846 STRINGSA("ddd',' MMM dd yy",""); /* Simple case */
847 SetLastError(0xdeadbeef);
850 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
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());
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());
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());
868
869 STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */
870 SetLastError(0xdeadbeef);
871 ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2);
873 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
874
875 STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */
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 */
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));
894 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
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);
902 &curtime, input, buffer, COUNTOF(buffer));
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());
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());
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());
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());
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());
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());
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());
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());
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());
982 broken(strncmp(buffer, Broken, strlen(Broken)) == 0) /* nt4 */,
983 "Expected '%s', got '%s'\n", Expected, buffer);
984}
985
986static void test_GetDateFormatEx(void)
987{
988 int ret;
989 SYSTEMTIME curtime;
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,
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);
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());
1016
1017 STRINGSW("",""); /* Invalid flag combination */
1018 SetLastError(0xdeadbeef);
1019 ret = pGetDateFormatEx(localeW, DATE_LONGDATE|DATE_SHORTDATE, NULL,
1020 input, NULL, 0, NULL);
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());
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 */
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());
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);
1079 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1080}
1081
1082static void test_GetDateFormatW(void)
1083{
1084 int ret;
1085 SYSTEMTIME curtime;
1088
1089 STRINGSW("",""); /* If flags is not zero then format must be NULL */
1093 {
1094 win_skip("GetDateFormatW is not implemented\n");
1095 return;
1096 }
1098 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1099 EXPECT_EQW;
1100
1101 STRINGSW("",""); /* NULL buffer, len > 0 */
1102 SetLastError(0xdeadbeef);
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());
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());
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());
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));
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
1163{
1164 static char szDot[] = { '.', '\0' };
1165 static char szComma[] = { ',', '\0' };
1166 static char szDollar[] = { '$', '\0' };
1167 int ret;
1171
1172 memset(&format, 0, sizeof(format));
1173
1174 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1175 SetLastError(0xdeadbeef);
1178 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1179
1180 STRINGSA("23,53",""); /* Invalid character --> Error */
1181 SetLastError(0xdeadbeef);
1184 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1185
1186 STRINGSA("--",""); /* Double '-' --> Error */
1187 SetLastError(0xdeadbeef);
1190 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1191
1192 STRINGSA("0-",""); /* Trailing '-' --> Error */
1193 SetLastError(0xdeadbeef);
1196 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1197
1198 STRINGSA("0..",""); /* Double '.' --> Error */
1199 SetLastError(0xdeadbeef);
1202 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1203
1204 STRINGSA(" 0.1",""); /* Leading space --> Error */
1205 SetLastError(0xdeadbeef);
1208 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1209
1210 STRINGSA("1234","$"); /* Length too small --> Write up to length chars */
1211 SetLastError(0xdeadbeef);
1214 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1215
1216 STRINGSA("2353",""); /* Format and flags given --> Error */
1217 SetLastError(0xdeadbeef);
1219 ok( !ret, "Expected ret == 0, got %d\n", ret);
1221 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1222
1223 STRINGSA("2353",""); /* Invalid format --> Error */
1224 SetLastError(0xdeadbeef);
1227 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1228
1229 STRINGSA("2353","$2,353.00"); /* Valid number */
1231 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1233
1234 STRINGSA("-2353","($2,353.00)"); /* Valid negative number */
1236 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1238
1239 STRINGSA("2353.1","$2,353.10"); /* Valid real number */
1241 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1243
1244 STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */
1246 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1248
1249 STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */
1251 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
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 */
1265 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1267
1268 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1269 STRINGSA("2353","$2353.0");
1271 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1273
1274 format.Grouping = 2; /* Group by 100's */
1275 STRINGSA("2353","$23,53.0");
1277 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1279
1280 STRINGSA("235","$235.0"); /* Grouping of a positive number */
1281 format.Grouping = 3;
1283 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1285
1286 STRINGSA("-235","$-235.0"); /* Grouping of a negative number */
1287 format.NegativeOrder = 2;
1289 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1291
1292 format.LeadingZero = 1; /* Always provide leading zero */
1293 STRINGSA(".5","$0.5");
1295 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1297
1298 format.PositiveOrder = CY_POS_RIGHT;
1299 STRINGSA("1","1.0$");
1301 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1303
1304 format.PositiveOrder = CY_POS_LEFT_SPACE;
1305 STRINGSA("1","$ 1.0");
1307 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1309
1310 format.PositiveOrder = CY_POS_RIGHT_SPACE;
1311 STRINGSA("1","1.0 $");
1313 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1315
1316 format.NegativeOrder = 0;
1317 STRINGSA("-1","($1.0)");
1319 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1321
1322 format.NegativeOrder = 1;
1323 STRINGSA("-1","-$1.0");
1325 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1327
1328 format.NegativeOrder = 2;
1329 STRINGSA("-1","$-1.0");
1331 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1333
1334 format.NegativeOrder = 3;
1335 STRINGSA("-1","$1.0-");
1337 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1339
1340 format.NegativeOrder = 4;
1341 STRINGSA("-1","(1.0$)");
1343 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1345
1346 format.NegativeOrder = 5;
1347 STRINGSA("-1","-1.0$");
1349 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1351
1352 format.NegativeOrder = 6;
1353 STRINGSA("-1","1.0-$");
1355 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1357
1358 format.NegativeOrder = 7;
1359 STRINGSA("-1","1.0$-");
1361 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1363
1364 format.NegativeOrder = 8;
1365 STRINGSA("-1","-1.0 $");
1367 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1369
1370 format.NegativeOrder = 9;
1371 STRINGSA("-1","-$ 1.0");
1373 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1375
1376 format.NegativeOrder = 10;
1377 STRINGSA("-1","1.0 $-");
1379 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1381
1382 format.NegativeOrder = 11;
1383 STRINGSA("-1","$ 1.0-");
1385 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1387
1388 format.NegativeOrder = 12;
1389 STRINGSA("-1","$ -1.0");
1391 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1393
1394 format.NegativeOrder = 13;
1395 STRINGSA("-1","1.0- $");
1397 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1399
1400 format.NegativeOrder = 14;
1401 STRINGSA("-1","($ 1.0)");
1403 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1405
1406 format.NegativeOrder = 15;
1407 STRINGSA("-1","(1.0 $)");
1409 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
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
1419static void test_GetNumberFormatA(void)
1420{
1421 static char szDot[] = { '.', '\0' };
1422 static char szComma[] = { ',', '\0' };
1423 int ret;
1427
1428 memset(&format, 0, sizeof(format));
1429
1430 STRINGSA("23",""); /* NULL output, length > 0 --> Error */
1431 SetLastError(0xdeadbeef);
1434 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1435
1436 STRINGSA("23,53",""); /* Invalid character --> Error */
1437 SetLastError(0xdeadbeef);
1440 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1441
1442 STRINGSA("--",""); /* Double '-' --> Error */
1443 SetLastError(0xdeadbeef);
1446 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1447
1448 STRINGSA("0-",""); /* Trailing '-' --> Error */
1449 SetLastError(0xdeadbeef);
1452 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1453
1454 STRINGSA("0..",""); /* Double '.' --> Error */
1455 SetLastError(0xdeadbeef);
1458 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1459
1460 STRINGSA(" 0.1",""); /* Leading space --> Error */
1461 SetLastError(0xdeadbeef);
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);
1470 "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
1471
1472 STRINGSA("2353",""); /* Format and flags given --> Error */
1473 SetLastError(0xdeadbeef);
1475 ok( !ret, "Expected ret == 0, got %d\n", ret);
1477 "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
1478
1479 STRINGSA("2353",""); /* Invalid format --> Error */
1480 SetLastError(0xdeadbeef);
1483 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1484
1485 STRINGSA("2353","2,353.00"); /* Valid number */
1487 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1489
1490 STRINGSA("-2353","-2,353.00"); /* Valid negative number */
1492 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1494
1495 STRINGSA("-353","-353.00"); /* test for off by one error in grouping */
1497 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1499
1500 STRINGSA("2353.1","2,353.10"); /* Valid real number */
1502 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1504
1505 STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */
1507 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1509
1510 STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */
1512 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
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 */
1524 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1526
1527 format.NumDigits = 1; /* 1 DP --> Expect decimal separator */
1528 STRINGSA("2353","2353.0");
1530 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1532
1533 format.Grouping = 2; /* Group by 100's */
1534 STRINGSA("2353","23,53.0");
1536 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1538
1539 STRINGSA("235","235.0"); /* Grouping of a positive number */
1540 format.Grouping = 3;
1542 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1544
1545 STRINGSA("-235","-235.0"); /* Grouping of a negative number */
1546 format.NegativeOrder = NEG_LEFT;
1548 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1550
1551 format.LeadingZero = 1; /* Always provide leading zero */
1552 STRINGSA(".5","0.5");
1554 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1556
1557 format.NegativeOrder = NEG_PARENS;
1558 STRINGSA("-1","(1.0)");
1560 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1562
1563 format.NegativeOrder = NEG_LEFT;
1564 STRINGSA("-1","-1.0");
1566 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1568
1569 format.NegativeOrder = NEG_LEFT_SPACE;
1570 STRINGSA("-1","- 1.0");
1572 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1574
1575 format.NegativeOrder = NEG_RIGHT;
1576 STRINGSA("-1","1.0-");
1578 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1580
1581 format.NegativeOrder = NEG_RIGHT_SPACE;
1582 STRINGSA("-1","1.0 -");
1584 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1586
1588
1589 if (IsValidLocale(lcid, 0))
1590 {
1591 STRINGSA("-12345","-12 345,00"); /* Try French formatting */
1592 Expected[3] = 160; /* Non breaking space */
1594 ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError());
1596 }
1597}
1598
1599static void test_GetNumberFormatEx(void)
1600{
1601 int ret;
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};
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));
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));
1624 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1625
1626 STRINGSW("--",""); /* Double '-' --> Error */
1627 ret = pGetNumberFormatEx(enW, 0, input, NULL, buffer, COUNTOF(buffer));
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));
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));
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));
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);
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));
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);
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));
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
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());
1778 }
1779}
1780
1784 const char *first;
1786 const char *second;
1788 int ret;
1789};
1790
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 },
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 },
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 },
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
1838static void test_CompareStringA(void)
1839{
1840 int ret, i;
1841 char a[256];
1843
1844 for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
1845 {
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
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);
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
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
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
1922 ok(ret == CSTR_GREATER_THAN, "`o vs /m CSTR_GREATER_THAN got %d\n", ret);
1923
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
1934 ok(ret == CSTR_GREATER_THAN, "`o vs -m CSTR_GREATER_THAN got %d\n", ret);
1935
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 */
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
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
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
1983static 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);
1994 ok(buf != NULL, "VirtualAlloc failed with %u\n", GetLastError());
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
2010 ok(success, "VirtualFree failed with %u\n", GetLastError());
2011}
2012
2014 const char *locale;
2016 const WCHAR first[2];
2017 const WCHAR second[2];
2021};
2022
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 */
2127 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2128 },
2129 { /* 25 */
2131 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, FALSE
2132 },
2133 { /* 26 */
2135 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2136 },
2137 { /* 27 */
2139 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2140 },
2141 { /* 28 */
2143 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2144 },
2145 { /* 29 */
2147 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, -1, TRUE
2148 },
2149 /* with NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE */
2150 { /* 30 */
2152 {'i',0}, {'I',0}, CSTR_GREATER_THAN, CSTR_EQUAL, TRUE
2153 },
2154 { /* 31 */
2156 {'i',0}, {0x130,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2157 },
2158 { /* 32 */
2160 {'i',0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2161 },
2162 { /* 33 */
2164 {'I',0}, {0x130,0}, CSTR_LESS_THAN, -1, TRUE
2165 },
2166 { /* 34 */
2168 {'I',0}, {0x131,0}, CSTR_EQUAL, CSTR_LESS_THAN, TRUE
2169 },
2170 { /* 35 */
2172 {0x130,0}, {0x131,0}, CSTR_GREATER_THAN, CSTR_LESS_THAN, TRUE
2173 }
2174};
2175
2176static 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 {
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
2202static const DWORD lcmap_invalid_flags[] = {
2203 0,
2228};
2229
2230static 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);
2240 lower_case, -1, buf, sizeof(buf));
2241 ok(ret == lstrlenA(lower_case) + 1,
2242 "ret %d, error %d, expected value %d\n",
2244 ok(!memcmp(buf, lower_case, ret), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2245
2247 upper_case, -1, buf, sizeof(buf));
2248 ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
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);
2257 lower_case, -1, buf, sizeof(buf));
2259 "LCMapStringA (flag %08x) unexpected error code %d\n",
2261 ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
2263 }
2264
2265 /* test 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",
2271 ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
2272
2273 /* test 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",
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);
2284 lower_case, -1, buf, 4);
2286 "should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
2287
2288 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
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",
2299 ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
2300 }
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",
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);
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 */
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");
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 */
2337 upper_case, -1, buf, sizeof(buf));
2338 ok(ret, "LCMapStringA must succeed\n");
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 */
2350 lower_case, -1, buf, sizeof(buf));
2351 ok(ret, "LCMapStringA must succeed\n");
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");
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");
2369 lower_case, -1, buf, sizeof(buf));
2370 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
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");
2377 lower_case, -1, buf, sizeof(buf));
2378 ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
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);
2385 ok(!ret, "LCMapStringA should fail with srclen = 0\n");
2387 "unexpected error code %d\n", GetLastError());
2388}
2389
2391
2393{
2394 static const WCHAR japanese_text[] = {
2395 0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2396 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
2397 };
2398 static const WCHAR hiragana_text[] = {
2399 0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
2400 0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
2401 };
2402 static const WCHAR katakana_text[] = {
2403 0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
2404 0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
2405 };
2406 static const WCHAR halfwidth_text[] = {
2407 0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
2408 0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
2409 };
2410 int ret, ret2, i;
2411 WCHAR buf[256], buf2[256];
2412 char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
2413
2414 /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
2416 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2418 "%s ret %d, error %d, expected value %d\n", func_name,
2421 "Expected title case string\n");
2422
2423 /* test invalid flag combinations */
2424 for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
2425 lstrcpyW(buf, fooW);
2426 SetLastError(0xdeadbeef);
2428 lower_case, -1, buf, sizeof(buf));
2430 "%s (flag %08x) unexpected error code %d\n",
2432 ok(!ret, "%s (flag %08x) should return 0, got %d\n",
2434 }
2435
2436 /* test LCMAP_LOWERCASE */
2438 upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2439 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2441 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2442
2443 /* test LCMAP_UPPERCASE */
2445 lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2446 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2448 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2449
2450 /* test LCMAP_HIRAGANA */
2452 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2453 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2454 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2455 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2456
2457 buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
2458 ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
2459 ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
2460 ret, GetLastError());
2461 /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
2462 ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
2463 "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
2464
2465 /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
2467 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2468 ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2469 ret, GetLastError(), lstrlenW(katakana_text) + 1);
2470 ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
2471
2472 /* test LCMAP_FULLWIDTH */
2474 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2475 ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2476 ret, GetLastError(), lstrlenW(japanese_text) + 1);
2477 ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
2478
2479 ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
2480 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
2481
2482 /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
2483 (half-width katakana is converted into full-width hiragana) */
2485 halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2486 ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2487 ret, GetLastError(), lstrlenW(hiragana_text) + 1);
2488 ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
2489
2490 ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
2491 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2492
2493 /* test LCMAP_HALFWIDTH */
2495 japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
2496 ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2497 ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
2498 ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
2499
2500 ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
2501 ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
2502
2503 /* test buffer overflow */
2504 SetLastError(0xdeadbeef);
2506 lower_case, -1, buf, 4);
2508 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2509
2510 /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
2511 Thus, it requires two WCHARs. */
2512 buf[0] = 0x30ac;
2513 SetLastError(0xdeadbeef);
2514 ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
2516 "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
2517
2518 /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
2521 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2522 ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2524 ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2525
2528 buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
2529 ok(ret == lstrlenW(upper_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2531 ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2532
2533 /* otherwise src == dst should fail */
2534 SetLastError(0xdeadbeef);
2536 buf, 10, buf, sizeof(buf));
2537 ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
2538 GetLastError() == ERROR_INVALID_PARAMETER /* Win7+ */,
2539 "%s unexpected error code %d\n", func_name, GetLastError());
2540 ok(!ret, "%s src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n", func_name);
2541
2542 /* test whether '\0' is always appended */
2544 upper_case, -1, buf, sizeof(buf));
2545 ok(ret, "%s func_ptr must succeed\n", func_name);
2546 ret2 = func_ptr(LCMAP_SORTKEY,
2547 upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
2548 ok(ret, "%s func_ptr must succeed\n", func_name);
2549 ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2550 ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2551
2552 /* test LCMAP_SORTKEY | NORM_IGNORECASE */
2554 upper_case, -1, buf, sizeof(buf));
2555 ok(ret, "%s func_ptr must succeed\n", func_name);
2556 ret2 =