ReactOS  0.4.13-dev-235-g7373cb3
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 
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);
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,
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)
116  X(LocaleNameToLCID);
117  X(LCIDToLocaleName);
118  X(LCMapStringEx);
119  X(FoldStringA);
120  X(FoldStringW);
125  X(IdnToAscii);
126  X(IdnToUnicode);
127  X(GetLocaleInfoEx);
128  X(IsValidLocaleName);
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 
164 static 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);
185  memset(buffer, 0, 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 
193  if (len) {
194  SetLastError(0xdeadbeef);
195  memset(buffer, 0, 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 */
207  SetLastError(0xdeadbeef);
208  memset(buffer, 0, 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));
221  ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
222 
223  SetLastError(0xdeadbeef);
224  memset(buffer, 0, COUNTOF(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));
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 
280 static 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  {
334  LANGID langid;
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 
428 static 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());
467  EXPECT_LENA;
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());
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());
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 
623 static 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());
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());
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());
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());
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 
819 static 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);
848  ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer));
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());
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());
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);
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 */
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());
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);
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());
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());
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());
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());
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 
986 static 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 
1082 static void test_GetDateFormatW(void)
1083 {
1084  int ret;
1085  SYSTEMTIME curtime;
1088 
1089  STRINGSW("",""); /* If flags is not zero then format must be NULL */
1091  input, buffer, COUNTOF(buffer));
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 
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;
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 
1419 static 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 
1599 static 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 },
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];
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 
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 
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 
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 */
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 
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);
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 
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 
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,
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);
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 
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",
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 */
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);
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",
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  }
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);
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",
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");
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");
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));
2417  todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
2418  "%s ret %d, error %d, expected value %d\n", func_name,
2419  ret, GetLastError(), lstrlenW(title_case) + 1);
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,
2440  ret, GetLastError(), lstrlenW(upper_case) + 1);
2441  ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2442 
2443  /* test LCMAP_UPPERCASE */
2445  lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2446  ok(ret == lstrlenW(lower_case) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
2447  ret, GetLastError(), lstrlenW(lower_case) + 1);
2448  ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
2449 
2450  /* test LCMAP_HIRAGANA */
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,
2523  ret, GetLastError(), lstrlenW(lower_case) + 1);
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,
2530  ret, GetLastError(), lstrlenW(lower_case) + 1);
2531  ok(!lstrcmpW(buf, lower_case), "%s string compare mismatch\n", func_name);
2532 
2533  /* otherwise src == dst should fail */
2534  SetLastError(0xdeadbeef);
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 = func_ptr(LCMAP_SORTKEY,
2557  lower_case, -1, buf2, sizeof(buf2));
2558  ok(ret2, "%s func_ptr must succeed\n", func_name);
2559  ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2560  ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2561 
2562  /* Don't test LCMAP_SORTKEY | NORM_IGNORENONSPACE, produces different
2563  results from plain LCMAP_SORTKEY on Vista */
2564 
2565  /* test LCMAP_SORTKEY | NORM_IGNORESYMBOLS */
2567  lower_case, -1, buf, sizeof(buf));
2568  ok(ret, "%s func_ptr must succeed\n", func_name);
2569  ret2 = func_ptr(LCMAP_SORTKEY,
2570  symbols_stripped, -1, buf2, sizeof(buf2));
2571  ok(ret2, "%s func_ptr must succeed\n", func_name);
2572  ok(ret == ret2, "%s lengths of sort keys must be equal\n", func_name);
2573  ok(!lstrcmpA(p_buf, p_buf2), "%s sort keys must be equal\n", func_name);
2574 
2575  /* test NORM_IGNORENONSPACE */
2576  lstrcpyW(buf, fooW);
2578  lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2579  ok(ret == lstrlenW(lower_case) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2580  lstrlenW(lower_case) + 1, ret);
2581  ok(!lstrcmpW(buf, lower_case), "%s string comparison mismatch\n", func_name);
2582 
2583  /* test NORM_IGNORESYMBOLS */
2584  lstrcpyW(buf, fooW);
2586  lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2587  ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2588  lstrlenW(symbols_stripped) + 1, ret);
2589  ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2590 
2591  /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
2592  lstrcpyW(buf, fooW);
2594  lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2595  ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
2596  lstrlenW(symbols_stripped) + 1, ret);
2597  ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
2598 
2599  /* test srclen = 0 */
2600  SetLastError(0xdeadbeef);
2601  ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
2602  ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name);
2604  "%s unexpected error code %d\n", func_name, GetLastError());
2605 }
2606 
2608 {
2610 }
2611 
2612 static void test_LCMapStringW(void)
2613 {
2614  int ret;
2615  WCHAR buf[256];
2616 
2617  trace("testing LCMapStringW\n");
2618 
2619  SetLastError(0xdeadbeef);
2620  ret = LCMapStringW((LCID)-1, LCMAP_LOWERCASE, upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
2621  todo_wine {
2622  ok(!ret, "LCMapStringW should fail with bad lcid\n");
2623  ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2624  }
2625 
2627 }
2628 
2630 {
2631  return pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, flags, src, srclen, dst, dstlen, NULL, NULL, 0);
2632 }
2633 
2634 static void test_LCMapStringEx(void)
2635 {
2636  int ret;
2637  WCHAR buf[256];
2638 
2639  if (!pLCMapStringEx)
2640  {
2641  win_skip( "LCMapStringEx not available\n" );
2642  return;
2643  }
2644 
2645  trace("testing LCMapStringEx\n");
2646 
2647  SetLastError(0xdeadbeef);
2648  ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
2649  upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
2650  todo_wine {
2651  ok(!ret, "LCMapStringEx should fail with bad locale name\n");
2652  ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError());
2653  }
2654 
2655  /* test reserved parameters */
2656  ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2657  upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 1);
2658  ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2659  ret, GetLastError(), lstrlenW(upper_case) + 1);
2660  ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2661 
2662  ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2663  upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, (void*)1, 0);
2664  ok(ret == lstrlenW(upper_case) + 1, "ret %d, error %d, expected value %d\n",
2665  ret, GetLastError(), lstrlenW(upper_case) + 1);
2666  ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
2667 
2668  /* crashes on native */
2669  if(0)
2670  ret = pLCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_LOWERCASE,
2671  upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), (void*)1, NULL, 0);
2672 
2674 }
2675 
2680  int todo;
2681 };
2682 
2684  { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
2685  { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
2686  { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
2687  { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
2688  { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
2689  { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
2690  { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
2691  { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
2692  { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
2693  { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
2694  { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
2695  { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
2696  { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
2697  { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
2698  { {0} }
2699 };
2700 
2701 static void test_LocaleNameToLCID(void)
2702 {
2703  LCID lcid;
2704  INT ret;
2706  static const WCHAR enW[] = {'e','n',0};
2707  static const WCHAR esesW[] = {'e','s','-','e','s',0};
2708  static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
2709  static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
2710  static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
2711  static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
2712  static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
2713  static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
2714 
2715  if (!pLocaleNameToLCID)
2716  {
2717  win_skip( "LocaleNameToLCID not available\n" );
2718  return;
2719  }
2720 
2721  /* special cases */
2722  buffer[0] = 0;
2723