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