#include <stdarg.h>
#include <stdio.h>
+#undef WINVER
+#define WINVER 0x0600
+
#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
static HMODULE hKernel32;
static WORD enumCount;
-typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
- DWORD, LONG_PTR);
-static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
-typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
- LGRPID, DWORD, LONG_PTR);
-static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
-typedef BOOL (WINAPI *EnumUILanguagesAFn)(UILANGUAGE_ENUMPROC,
- DWORD, LONG_PTR);
-static EnumUILanguagesAFn pEnumUILanguagesA;
-
-typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
-static FoldStringAFn pFoldStringA;
-typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
-static FoldStringWFn pFoldStringW;
-
-typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
-static IsValidLanguageGroupFn pIsValidLanguageGroup;
+static BOOL (WINAPI *pEnumSystemLanguageGroupsA)(LANGUAGEGROUP_ENUMPROC, DWORD, LONG_PTR);
+static BOOL (WINAPI *pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC, LGRPID, DWORD, LONG_PTR);
+static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROC, DWORD, LONG_PTR);
+static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
+static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
+static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
+static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
+static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
+static BOOL (WINAPI *pIsValidLanguageGroup)(LGRPID, DWORD);
+static INT (WINAPI *pIdnToNameprepUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
+static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT);
+static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT);
static void InitFunctionPointers(void)
{
hKernel32 = GetModuleHandleA("kernel32");
pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
+ pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
+ pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
+ pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
+ pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
+ pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
+ pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
}
#define eq(received, expected, label, type) \
}
}
+struct comparestringa_entry {
+ LCID lcid;
+ DWORD flags;
+ const char *first;
+ int first_len;
+ const char *second;
+ int second_len;
+ int ret;
+};
+
+static const struct comparestringa_entry comparestringa_data[] = {
+ { LOCALE_SYSTEM_DEFAULT, 0, "EndDialog", -1, "_Property", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0070", -1, "_IEWWBrowserComp", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "r", -1, "\\", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "osp_vba.sreg0031", -1, "OriginalDatabase", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1, CSTR_LESS_THAN },
+ /* hyphen and apostrophe are treated differently depending on whether SORT_STRINGSORT specified or not */
+ { LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1, CSTR_LESS_THAN },
+ { LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1, CSTR_GREATER_THAN },
+ { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9, CSTR_EQUAL },
+ { LOCALE_SYSTEM_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10, CSTR_LESS_THAN }
+};
static void test_CompareStringA(void)
{
- int ret;
+ int ret, i;
LCID lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT);
+ for (i = 0; i < sizeof(comparestringa_data)/sizeof(struct comparestringa_entry); i++)
+ {
+ const struct comparestringa_entry *entry = &comparestringa_data[i];
+
+ ret = CompareStringA(entry->lcid, entry->flags, entry->first, entry->first_len,
+ entry->second, entry->second_len);
+ ok(ret == entry->ret, "%d: got %d, expected %d\n", i, ret, entry->ret);
+ }
+
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", -1, "Salute", -1);
ok (ret== 1, "(Salut/Salute) Expected 1, got %d\n", ret);
ret = lstrcmpA(NULL, "");
ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
- ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
- ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
- ok( ret == 3, "r vs \\ ... expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
- ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
- ok( ret == 3, "AAA vs aaa expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
- ok( ret == 1, "AAA vs aab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
- ok( ret == 1, "AAA vs Aab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
- ok( ret == 1, ".AAA vs Aab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
- ok( ret == 1, ".AAA vs A.ab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
- ok( ret == 1, "aa vs AB expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
- ok( ret == 1, "aa vs Aab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
- ok( ret == 3, "aB vs Aab expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
- ok( ret == 1, "Ba vs bab expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
- ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
- ok( ret == 3, "a vs { expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
- ok( ret == 3, "A vs { expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
- ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
- ok(ret == 1, "3.5 vs 4.0 expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
- ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d\n", ret);
-
- /* hyphen and apostrophe are treated differently depending on
- * whether SORT_STRINGSORT specified or not
- */
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
- ok(ret == 3, "-o vs /m expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
- ok(ret == 1, "/m vs -o expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
- ok(ret == 1, "-o vs /m expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
- ok(ret == 3, "/m vs -o expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
- ok(ret == 3, "'o vs /m expected 3, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
- ok(ret == 1, "/m vs 'o expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
- ok(ret == 1, "'o vs /m expected 1, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
- ok(ret == 3, "/m vs 'o expected 3, got %d\n", ret);
if (0) { /* this requires collation table patch to make it MS compatible */
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
ok(ret == 1, "-m vs `o expected 1, got %d\n", ret);
}
- ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
- ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d\n", ret);
-
- ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
- ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d\n", ret);
/* WinXP handles embedded NULLs differently than earlier versions */
ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
ret = lstrcmpi("#", ".");
todo_wine ok(ret == -1, "\"#\" vs \".\" expected -1, got %d\n", ret);
+
+ lcid = MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
+
+ /* \xB9 character lies between a and b */
+ ret = CompareStringA(lcid, 0, "a", 1, "\xB9", 1);
+ todo_wine ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be greater than \'a\'\n");
+ ret = CompareStringA(lcid, 0, "\xB9", 1, "b", 1);
+ ok(ret == CSTR_LESS_THAN, "\'\\xB9\' character should be smaller than \'b\'\n");
}
static void test_LCMapStringA(void)
"unexpected error code %d\n", GetLastError());
}
+static void test_LocaleNames(void)
+{
+ LCID lcid;
+ INT ret;
+ WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
+
+ if (!pLocaleNameToLCID)
+ {
+ win_skip( "LocaleNameToLCID not available\n" );
+ return;
+ }
+
+ /* special cases */
+ buffer[0] = 0;
+ lcid = pLocaleNameToLCID(LOCALE_NAME_USER_DEFAULT, 0);
+ ok(lcid == GetUserDefaultLCID() || broken(GetLastError() == ERROR_INVALID_PARAMETER /* Vista */),
+ "Expected lcid == %08x, got %08x, error %d\n", lcid, GetUserDefaultLCID(), GetLastError());
+ ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
+ ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
+ trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
+
+ buffer[0] = 0;
+ lcid = pLocaleNameToLCID(LOCALE_NAME_SYSTEM_DEFAULT, 0);
+ todo_wine ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected lcid != 0, got %08x, error %d\n", lcid, GetLastError());
+ ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
+ ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
+ trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
+
+ buffer[0] = 0;
+ lcid = pLocaleNameToLCID(LOCALE_NAME_INVARIANT, 0);
+ todo_wine ok(lcid == 0x7F, "Expected lcid = 0x7F, got %08x, error %d\n", lcid, GetLastError());
+ ret = pLCIDToLocaleName(lcid, buffer, LOCALE_NAME_MAX_LENGTH, 0);
+ ok(ret > 0, "Expected ret > 0, got %d, error %d\n", ret, GetLastError());
+ trace("%08x, %s\n", lcid, wine_dbgstr_w(buffer));
+}
+
/* this requires collation table patch to make it MS compatible */
static const char * const strings_sorted[] =
{
{
'W','i','n','e',0x0348,0x0551,0x1323,0x280d,'W','i','n','e','\0'
};
+ static const WCHAR foldczone_todo_src[] =
+ {
+ 0x3c5,0x308,0x6a,0x30c,0xa0,0xaa,0
+ };
+ static const WCHAR foldczone_todo_dst[] =
+ {
+ 0x3cb,0x1f0,' ','a',0
+ };
+ static const WCHAR foldczone_todo_broken_dst[] =
+ {
+ 0x3cb,0x1f0,0xa0,0xaa,0
+ };
static const WCHAR ligatures_src[] =
{
'W', 'i', 'n', 'e', 0x03a6, 0x03b9, 0x03bd, 0x03b5,
ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
/* Wine (correctly) maps all Unicode 4.0+ digits */
- isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
+ isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF || ch == 0x19da ||
(ch >= 0x1369 && ch <= 0x1371),
"MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
}
ok(!memcmp(dst, foldczone_dst, sizeof(foldczone_dst)),
"MAP_FOLDCZONE: Expanded incorrectly\n");
+ ret = pFoldStringW(MAP_FOLDCZONE|MAP_PRECOMPOSED, foldczone_todo_src, -1, dst, 256);
+ todo_wine ok(ret == sizeof(foldczone_todo_dst)/sizeof(foldczone_todo_dst[0]),
+ "Got %d, error %d\n", ret, GetLastError());
+ todo_wine ok(!memcmp(dst, foldczone_todo_dst, sizeof(foldczone_todo_dst))
+ || broken(!memcmp(dst, foldczone_todo_broken_dst, sizeof(foldczone_todo_broken_dst))),
+ "MAP_FOLDCZONE: Expanded incorrectly (%s)\n", wine_dbgstr_w(dst));
+
/* MAP_EXPAND_LIGATURES */
SetLastError(0);
ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256);
pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0);
}
+static BOOL CALLBACK enum_func( LPWSTR name, DWORD flags, LPARAM lparam )
+{
+ trace( "%s %x\n", wine_dbgstr_w(name), flags );
+ return TRUE;
+}
+
+static void test_EnumSystemLocalesEx(void)
+{
+ BOOL ret;
+
+ if (!pEnumSystemLocalesEx)
+ {
+ win_skip( "EnumSystemLocalesEx not available\n" );
+ return;
+ }
+ SetLastError( 0xdeadbeef );
+ ret = pEnumSystemLocalesEx( enum_func, LOCALE_ALL, 0, (void *)1 );
+ ok( !ret, "should have failed\n" );
+ ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+ SetLastError( 0xdeadbeef );
+ ret = pEnumSystemLocalesEx( enum_func, 0, 0, NULL );
+ ok( ret, "failed err %u\n", GetLastError() );
+}
static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum,
LONG_PTR lParam)
/* IDATE */
SetLastError(0);
- bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA);
+ bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, "test_SetLocaleInfoA");
ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
"Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
/* ILDATE */
SetLastError(0);
- bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA);
+ bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, "test_SetLocaleInfoA");
ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS,
"Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
}
}
}
+/*
+ * The CT_TYPE1 has varied over windows version.
+ * The current target for correct behavior is windows 7.
+ * There was a big shift between windows 2000 (first introduced) and windows Xp
+ * Most of the old values below are from windows 2000.
+ * A smaller subset of changes happened between windows Xp and Window vista/7
+ */
+static void test_GetStringTypeW(void)
+{
+ static const WCHAR blanks[] = {0x9, 0x20, 0xa0, 0x3000, 0xfeff};
+ static const WORD blanks_new[] = {C1_SPACE | C1_CNTRL | C1_BLANK | C1_DEFINED,
+ C1_SPACE | C1_BLANK | C1_DEFINED,
+ C1_SPACE | C1_BLANK | C1_DEFINED,
+ C1_SPACE | C1_BLANK | C1_DEFINED,
+ C1_CNTRL | C1_BLANK | C1_DEFINED};
+ static const WORD blanks_old[] ={C1_SPACE | C1_CNTRL | C1_BLANK,
+ C1_SPACE | C1_BLANK,
+ C1_SPACE | C1_BLANK,
+ C1_SPACE | C1_BLANK,
+ C1_SPACE | C1_BLANK};
+
+ static const WCHAR undefined[] = {0x378, 0x379, 0x604, 0xfff8, 0xfffe};
+
+ /* Lu, Ll, Lt */
+ static const WCHAR alpha[] = {0x47, 0x67, 0x1c5};
+ static const WORD alpha_old[] = {C1_UPPER | C1_ALPHA,
+ C1_LOWER | C1_ALPHA,
+ C1_UPPER | C1_LOWER | C1_ALPHA,
+ C1_ALPHA};
+
+ /* Sk, Sk, Mn, So, Me */
+ static const WCHAR oldpunc[] = { 0x2c2, 0x2e5, 0x322, 0x482, 0x6de,
+ /* Sc, Sm, No,*/
+ 0xffe0, 0xffe9, 0x2153};
+
+ /* Lm, Nl, Cf, 0xad(Cf), 0x1f88 (Lt), Lo, Mc */
+ static const WCHAR changed[] = {0x2b0, 0x2160, 0x600, 0xad, 0x1f88, 0x294, 0x903};
+ static const WORD changed_old[] = { C1_PUNCT, C1_PUNCT, 0, C1_PUNCT, C1_UPPER | C1_ALPHA, C1_ALPHA, C1_PUNCT };
+ static const WORD changed_xp[] = {C1_ALPHA | C1_DEFINED,
+ C1_ALPHA | C1_DEFINED,
+ C1_CNTRL | C1_DEFINED,
+ C1_PUNCT | C1_DEFINED,
+ C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
+ C1_ALPHA | C1_LOWER | C1_DEFINED,
+ C1_ALPHA | C1_DEFINED };
+ static const WORD changed_new[] = { C1_ALPHA | C1_DEFINED,
+ C1_ALPHA | C1_DEFINED,
+ C1_CNTRL | C1_DEFINED,
+ C1_PUNCT | C1_CNTRL | C1_DEFINED,
+ C1_UPPER | C1_LOWER | C1_ALPHA | C1_DEFINED,
+ C1_ALPHA | C1_DEFINED,
+ C1_DEFINED
+ };
+ /* Pc, Pd, Ps, Pe, Pi, Pf, Po*/
+ static const WCHAR punct[] = { 0x5f, 0x2d, 0x28, 0x29, 0xab, 0xbb, 0x21 };
+
+ static const WCHAR punct_special[] = {0x24, 0x2b, 0x3c, 0x3e, 0x5e, 0x60,
+ 0x7c, 0x7e, 0xa2, 0xbe, 0xd7, 0xf7};
+ static const WCHAR digit_special[] = {0xb2, 0xb3, 0xb9};
+ static const WCHAR lower_special[] = {0x2071, 0x207f};
+ static const WCHAR cntrl_special[] = {0x070f, 0x200c, 0x200d,
+ 0x200e, 0x200f, 0x202a, 0x202b, 0x202c, 0x202d, 0x202e,
+ 0x206a, 0x206b, 0x206c, 0x206d, 0x206e, 0x206f, 0xfeff,
+ 0xfff9, 0xfffa, 0xfffb};
+ static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
+
+ WORD types[20];
+ int i;
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, blanks, 5, types);
+ for (i = 0; i < 5; i++)
+ 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]);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, alpha, 3, types);
+ for (i = 0; i < 3; i++)
+ 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]));
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, undefined, 5, types);
+ for (i = 0; i < 5; i++)
+ ok(types[i] == 0, "incorrect types returned for %x -> (%x != 0)\n",undefined[i], types[i]);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, oldpunc, 8, types);
+ for (i = 0; i < 8; i++)
+ 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);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, changed, 7, types);
+ for (i = 0; i < 7; i++)
+ 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]);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, punct, 7, types);
+ for (i = 0; i < 7; i++)
+ 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));
+
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, punct_special, 12, types);
+ for (i = 0; i < 12; i++)
+ 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);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, digit_special, 3, types);
+ for (i = 0; i < 3; i++)
+ 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);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, lower_special, 2, types);
+ for (i = 0; i < 2; i++)
+ 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);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, cntrl_special, 20, types);
+ for (i = 0; i < 20; i++)
+ 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);
+
+ memset(types,0,sizeof(types));
+ GetStringTypeW(CT_CTYPE1, space_special, 3, types);
+ for (i = 0; i < 3; i++)
+ 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 );
+}
+
+static void test_IdnToNameprepUnicode(void)
+{
+ struct {
+ DWORD in_len;
+ const WCHAR in[64];
+ DWORD ret;
+ const WCHAR out[64];
+ DWORD flags;
+ DWORD err;
+ DWORD todo;
+ } test_data[] = {
+ {
+ 5, {'t','e','s','t',0},
+ 5, {'t','e','s','t',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 3, {'a',0xe111,'b'},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 4, {'t',0,'e',0},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 1, {'T',0},
+ 1, {'T',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 1, {0},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 6, {' ','-','/','[',']',0},
+ 6, {' ','-','/','[',']',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 3, {'a','-','a'},
+ 3, {'a','-','a'},
+ IDN_USE_STD3_ASCII_RULES, 0xdeadbeef
+ },
+ {
+ 3, {'a','a','-'},
+ 0, {0},
+ IDN_USE_STD3_ASCII_RULES, ERROR_INVALID_NAME
+ },
+ { /* FoldString is not working as expected when MAP_FOLDCZONE is specified (composition+compatibility) */
+ 10, {'T',0xdf,0x130,0x143,0x37a,0x6a,0x30c,' ',0xaa,0},
+ 12, {'t','s','s','i',0x307,0x144,' ',0x3b9,0x1f0,' ','a',0},
+ 0, 0xdeadbeef, TRUE
+ },
+ {
+ 11, {'t',0xad,0x34f,0x1806,0x180b,0x180c,0x180d,0x200b,0x200c,0x200d,0},
+ 2, {'t',0},
+ 0, 0xdeadbeef
+ },
+ { /* Another example of incorrectly working FoldString (composition) */
+ 2, {0x3b0, 0},
+ 2, {0x3b0, 0},
+ 0, 0xdeadbeef, TRUE
+ },
+ {
+ 2, {0x221, 0},
+ 0, {0},
+ 0, ERROR_NO_UNICODE_TRANSLATION
+ },
+ {
+ 2, {0x221, 0},
+ 2, {0x221, 0},
+ IDN_ALLOW_UNASSIGNED, 0xdeadbeef
+ },
+ {
+ 5, {'a','.','.','a',0},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 3, {'a','.',0},
+ 3, {'a','.',0},
+ 0, 0xdeadbeef
+ },
+ };
+
+ WCHAR buf[1024];
+ DWORD i, ret, err;
+
+ if (!pIdnToNameprepUnicode)
+ {
+ win_skip("IdnToNameprepUnicode is not available\n");
+ return;
+ }
+
+ ret = pIdnToNameprepUnicode(0, test_data[0].in,
+ test_data[0].in_len, NULL, 0);
+ ok(ret == test_data[0].ret, "ret = %d\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(0, test_data[1].in,
+ test_data[1].in_len, NULL, 0);
+ err = GetLastError();
+ ok(ret == test_data[1].ret, "ret = %d\n", ret);
+ ok(err == test_data[1].err, "err = %d\n", err);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(0, test_data[0].in, -1,
+ buf, sizeof(buf)/sizeof(WCHAR));
+ err = GetLastError();
+ ok(ret == test_data[0].ret, "ret = %d\n", ret);
+ ok(err == 0xdeadbeef, "err = %d\n", err);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(0, test_data[0].in, -2,
+ buf, sizeof(buf)/sizeof(WCHAR));
+ err = GetLastError();
+ ok(ret == 0, "ret = %d\n", ret);
+ ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(0, test_data[0].in, 0,
+ buf, sizeof(buf)/sizeof(WCHAR));
+ err = GetLastError();
+ ok(ret == 0, "ret = %d\n", ret);
+ ok(err == ERROR_INVALID_NAME, "err = %d\n", err);
+
+ ret = pIdnToNameprepUnicode(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES,
+ test_data[0].in, -1, buf, sizeof(buf)/sizeof(WCHAR));
+ ok(ret == test_data[0].ret, "ret = %d\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(0, NULL, 0, NULL, 0);
+ err = GetLastError();
+ ok(ret == 0, "ret = %d\n", ret);
+ ok(err == ERROR_INVALID_PARAMETER, "err = %d\n", err);
+
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(4, NULL, 0, NULL, 0);
+ err = GetLastError();
+ ok(ret == 0, "ret = %d\n", ret);
+ ok(err == ERROR_INVALID_FLAGS, "err = %d\n", err);
+
+ for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = pIdnToNameprepUnicode(test_data[i].flags, test_data[i].in,
+ test_data[i].in_len, buf, sizeof(buf)/sizeof(WCHAR));
+ err = GetLastError();
+ if(!test_data[i].todo) {
+ ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
+ ok(err == test_data[i].err, "%d) err = %d\n", i, err);
+ ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
+ "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
+ }else {
+ todo_wine ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
+ "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
+ }
+ }
+}
+
+static void test_IdnToAscii(void)
+{
+ struct {
+ DWORD in_len;
+ const WCHAR in[64];
+ DWORD ret;
+ const WCHAR out[64];
+ DWORD flags;
+ DWORD err;
+ } test_data[] = {
+ {
+ 5, {'T','e','s','t',0},
+ 5, {'T','e','s','t',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 5, {'T','e',0x017c,'s','t',0},
+ 12, {'x','n','-','-','t','e','s','t','-','c','b','b',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 12, {'t','e',0x0105,'s','t','.','t','e',0x017c,'s','t',0},
+ 26, {'x','n','-','-','t','e','s','t','-','c','t','a','.','x','n','-','-','t','e','s','t','-','c','b','b',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 3, {0x0105,'.',0},
+ 9, {'x','n','-','-','2','d','a','.',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 10, {'h','t','t','p',':','/','/','t',0x0106,0},
+ 17, {'x','n','-','-','h','t','t','p',':','/','/','t','-','7','8','a',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 10, {0x4e3a,0x8bf4,0x4e0d,0x4ed6,0x5011,0x10d,0x11b,0x305c,0x306a,0},
+ 35, {'x','n','-','-','b','e','a','2','a','1','6','3','1','a','v','b','a',
+ 'v','4','4','t','y','h','a','3','2','b','9','1','e','g','s','2','t',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 2, {0x221,0},
+ 8, {'x','n','-','-','6','l','a',0},
+ IDN_ALLOW_UNASSIGNED, 0xdeadbeef
+ },
+ };
+
+ WCHAR buf[1024];
+ DWORD i, ret, err;
+
+ if (!pIdnToAscii)
+ {
+ win_skip("IdnToAscii is not available\n");
+ return;
+ }
+
+ for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = pIdnToAscii(test_data[i].flags, test_data[i].in,
+ test_data[i].in_len, buf, sizeof(buf));
+ err = GetLastError();
+ ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
+ ok(err == test_data[i].err, "%d) err = %d\n", i, err);
+ ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
+ "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
+ }
+}
+
+static void test_IdnToUnicode(void)
+{
+ struct {
+ DWORD in_len;
+ const WCHAR in[64];
+ DWORD ret;
+ const WCHAR out[64];
+ DWORD flags;
+ DWORD err;
+ } test_data[] = {
+ {
+ 5, {'T','e','s','.',0},
+ 5, {'T','e','s','.',0},
+ 0, 0xdeadbeef
+ },
+ {
+ 2, {0x105,0},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 33, {'x','n','-','-','4','d','b','c','a','g','d','a','h','y','m','b',
+ 'x','e','k','h','e','h','6','e','0','a','7','f','e','i','0','b',0},
+ 23, {0x05dc,0x05de,0x05d4,0x05d4,0x05dd,0x05e4,0x05e9,0x05d5,0x05d8,
+ 0x05dc,0x05d0,0x05de,0x05d3,0x05d1,0x05e8,0x05d9,0x05dd,0x05e2,
+ 0x05d1,0x05e8,0x05d9,0x05ea,0},
+ 0, 0xdeadbeef
+ },
+ {
+ 34, {'t','e','s','t','.','x','n','-','-','k','d','a','9','a','g','5','e',
+ '9','j','n','f','s','j','.','x','n','-','-','p','d','-','f','n','a'},
+ 16, {'t','e','s','t','.',0x0105,0x0119,0x015b,0x0107,
+ 0x0142,0x00f3,0x017c,'.','p',0x0119,'d'},
+ 0, 0xdeadbeef
+ },
+ {
+ 64, {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
+ 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
+ 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
+ 'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'},
+ 0, {0},
+ 0, ERROR_INVALID_NAME
+ },
+ {
+ 8, {'x','n','-','-','6','l','a',0},
+ 2, {0x221,0},
+ IDN_ALLOW_UNASSIGNED, 0xdeadbeef
+ },
+ };
+
+ WCHAR buf[1024];
+ DWORD i, ret, err;
+
+ if (!pIdnToUnicode)
+ {
+ win_skip("IdnToUnicode is not available\n");
+ return;
+ }
+
+ for (i=0; i<sizeof(test_data)/sizeof(*test_data); i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = pIdnToUnicode(test_data[i].flags, test_data[i].in,
+ test_data[i].in_len, buf, sizeof(buf));
+ err = GetLastError();
+ ok(ret == test_data[i].ret, "%d) ret = %d\n", i, ret);
+ ok(err == test_data[i].err, "%d) err = %d\n", i, err);
+ ok(!memcmp(test_data[i].out, buf, ret*sizeof(WCHAR)),
+ "%d) buf = %s\n", i, wine_dbgstr_wn(buf, ret));
+ }
+}
+
START_TEST(locale)
{
InitFunctionPointers();
test_CompareStringA();
test_LCMapStringA();
test_LCMapStringW();
+ test_LocaleNames();
test_FoldStringA();
test_FoldStringW();
test_ConvertDefaultLocale();
test_EnumSystemLanguageGroupsA();
+ test_EnumSystemLocalesEx();
test_EnumLanguageGroupLocalesA();
test_SetLocaleInfoA();
test_EnumUILanguageA();
test_GetCPInfo();
+ test_GetStringTypeW();
+ test_IdnToNameprepUnicode();
+ test_IdnToAscii();
+ test_IdnToUnicode();
/* this requires collation table patch to make it MS compatible */
if (0) test_sorting();
}