This adds unit tests for these four functions: GetUserGeoID(); SetUserGeoID(); GetUserDefaultGeoName(); SetUserGeoName().
These are all functions I intend to improve and/or implement in the short future.
Signed-off-by: João Diogo Craveiro Ferreira devilj@outlook.pt --- dlls/kernel32/tests/locale.c | 319 +++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 81e74531ea..e3e46bfb53 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -108,6 +108,8 @@ static LANGID (WINAPI *pSetThreadUILanguage)(LANGID); static LANGID (WINAPI *pGetThreadUILanguage)(VOID); static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pFindStringOrdinal)(DWORD, LPCWSTR lpStringSource, INT, LPCWSTR, INT, BOOL); +static int (WINAPI *pGetUserDefaultGeoName)(LPWSTR, int); +static BOOL (WINAPI *pSetUserGeoName)(PWSTR);
static void InitFunctionPointers(void) { @@ -145,6 +147,8 @@ static void InitFunctionPointers(void) X(GetThreadUILanguage); X(NormalizeString); X(FindStringOrdinal); + X(GetUserDefaultGeoName); + X(SetUserGeoName);
mod = GetModuleHandleA("ntdll"); X(RtlUpcaseUnicodeChar); @@ -4745,6 +4749,317 @@ static void test_CompareStringOrdinal(void) } }
+static void test_GetUserGeoID(void) +{ + GEOID id; + todo_wine { + if (pGetUserDefaultGeoName && pSetUserGeoName) + { + ok(GEOID_NOT_AVAILABLE != GetUserGeoID(GEOCLASS_NATION), + "GEOCLASS_NATION: should never return GEOID_NOT_AVAILABLE when GeoName API is available.\n"); + ok(GEOID_NOT_AVAILABLE != GetUserGeoID(GEOCLASS_REGION), + "GEOCLASS_REGION: should never return GEOID_NOT_AVAILABLE when GeoName API is available.\n"); + } + else + win_skip("This platform allows GEOID_NOT_AVAILABLE to be returned.\n"); + } + + id = GetUserGeoID(GEOCLASS_ALL); + ok(id == GEOID_NOT_AVAILABLE, + "GEOCLASS_ALL: Expected GEOID_NOT_AVAILABLE, got %d.\n", id); + id = GetUserGeoID(12345); + ok(id == GEOID_NOT_AVAILABLE, + "Gibberish argument: Expected GEOID_NOT_AVAILABLE, got %d.\n", id); +} + +static void test_GetUserDefaultGeoName(void) +{ + todo_wine { + if (pGetUserDefaultGeoName && pSetUserGeoName) + { + WCHAR *name = malloc(sizeof(WCHAR) * 10); + int count = 0; + + if (!name) + { + trace("Couldn't allocate 20 bytes to store geo name. Aborting test!\n"); + return; + } + + SetLastError(ERROR_SUCCESS); + count = pGetUserDefaultGeoName(NULL, 10); + ok(count == 0 && (GetLastError() == ERROR_INVALID_PARAMETER), + "Expected count == 0, got %d; and expected last error = ERROR_INVALID_PARAMETER (87), got %d\n", + count, GetLastError()); + + count = pGetUserDefaultGeoName(NULL, -1); + ok(count == 0 && (GetLastError() == ERROR_INVALID_PARAMETER), + "Expected count == 0, got %d; and expected last error = ERROR_INVALID_PARAMETER (87), got %d\n", + count, GetLastError()); + + SetLastError(ERROR_SUCCESS); + count = pGetUserDefaultGeoName(name, 0); + ok(count > 0, "Expected character count > 0, got %d; last error was %d.\n", count, GetLastError()); + + count = pGetUserDefaultGeoName(name, 1); + ok(count == 0 && (GetLastError() == ERROR_INSUFFICIENT_BUFFER), + "Expected count == 0, got %d; and expected last error = ERROR_INSUFFICIENT_BUFFER (122), got %d\n", + count, GetLastError()); + + count = pGetUserDefaultGeoName(name, -1); + ok(count == 0 && (GetLastError() == ERROR_INVALID_PARAMETER), + "Expected count == 0, got %d; and expected last error = ERROR_INVALID_PARAMETER (87), got %d\n", + count, GetLastError()); + + free(name); + + SetLastError(ERROR_SUCCESS); + count = pGetUserDefaultGeoName(NULL, 0); + ok(count > 0, "Expected character count > 0, got %d; last error was %d.\n", count, GetLastError()); + if (count) + { + name = malloc(count * sizeof(WCHAR)); + if (name) + { + int result = pGetUserDefaultGeoName(name, count); + ok(result, + "Expected character count == %d, got %d; last error was %d.\n", + count, result, GetLastError()); + free(name); + } + else + trace("Couldn't allocate %d bytes to store geo name.\n", count); + } + } + else win_skip("GetUserDefaultGeoName: procedure not implemented on this platform.\n"); + } +} + +static void test_SetUserGeoID(void) +{ + BOOL status; + const int geoname_supported = (pGetUserDefaultGeoName && pSetUserGeoName); + + const GEOID original_nation = GetUserGeoID(GEOCLASS_NATION); + const GEOID original_region = GetUserGeoID(GEOCLASS_REGION); + int original_name_count = 0; /* We only need the char count. */ + + struct geopair { + GEOID id; + WCHAR name[4]; + }; + + struct testsuit { + const char *const stage; + struct geopair geo, geo_backup; + GEOCLASS geoclass; + }; + + struct testsuit const tests[] = { + {"GEOCLASS_NATION", {193, {'P','T',0}}, {56, {'C','U',0}}, GEOCLASS_NATION}, + {"GEOCLASS_REGION", {21206, {'0','5','7',0}}, {10039880, {'0','2','9',0}}, GEOCLASS_REGION} + }; + + struct testsuit const bad_args[] = { + {"invalid GEOID -1", {GEOID_NOT_AVAILABLE}}, + {"invalid GEOID 1", {1}} + }; + + if (geoname_supported) + original_name_count = pGetUserDefaultGeoName(NULL, 0); + + /* Invalid args */ + for (int i = 0; i < ARRAY_SIZE(bad_args); i++) + { + BOOL status; + + SetLastError(ERROR_SUCCESS); + + status = SetUserGeoID(bad_args[i].geo.id); + ok(!status && + (GetLastError() == ERROR_INVALID_PARAMETER || /* Vista+ */ + broken(GetLastError() == ERROR_SUCCESS)), /* WinXP */ + "Setting %s: got ret=%d (expected 0), error=%d (expected 87=ERROR_INVALID_PARAMETER)\n", + bad_args[i].stage, status, GetLastError()); + } + + for (int i = 0; i < ARRAY_SIZE(tests); i++) + { + const struct geopair *geo; + + if (original_nation != tests[i].geo.id) + geo = &tests[i].geo; + else + geo = &tests[i].geo_backup; + + SetLastError(ERROR_SUCCESS); + ok(status = SetUserGeoID(geo->id), + "%s: Setting to %d failed with last error: %d\n", tests[i].stage, geo->id, GetLastError()); + if (status) + { + const GEOID id = GetUserGeoID(tests[i].geoclass); + const int status = (id == geo->id); + ok(status, "%s: we just set it to %d but retrieved %d instead \n", tests[i].stage, geo->id, id); + + if (status) + { + todo_wine { + if (geoname_supported) + { + const int count = pGetUserDefaultGeoName(NULL, 0); + WCHAR *const name = malloc(count * sizeof(WCHAR)); + + if (name) + { + const int written = pGetUserDefaultGeoName(name, count); + const int status = (count == written); + + ok(status, + "%s: Failed to get geoname after setting ID to %d: got %d characters, expected %d\n", + tests[i].stage, id, written, count); + ok(!winetest_strcmpW(name, geo->name), + "%s: wrong geoname for ID %d: got %s, expected %s\n", + tests[i].stage, geo->id, wine_dbgstr_w(name), wine_dbgstr_w(geo->name)); + free(name); + } + else if (count > 0) + trace("Couldn't allocate memory to store geoname string! (Size = %lu bytes)\n", + count * sizeof(WCHAR)); + } + else + win_skip("%s: Can't check geoname: unsupported platform.\n", tests[i].stage); + } + } + } + } + + /* Best attempt at restoring original values */ + if (geoname_supported) + { + if (original_name_count <= 3) + { + SetUserGeoID(original_region); + SetUserGeoID(original_nation); + } + else + { + SetUserGeoID(original_nation); + SetUserGeoID(original_region); + } + } + else + { + const GEOID neutral = 39070; /* World */ + original_region != GEOID_NOT_AVAILABLE ? SetUserGeoID(original_region) : SetUserGeoID(neutral); + original_nation != GEOID_NOT_AVAILABLE ? SetUserGeoID(original_nation) : SetUserGeoID(neutral); + } +} + +static void test_SetUserGeoName(void) +{ + todo_wine + { + if (pGetUserDefaultGeoName && pSetUserGeoName) + { + struct geopair { + WCHAR *name; + GEOID id; + }; + + struct testsuit { + const char *stage; + BOOL exp_return; + int exp_error; + struct geopair geo, geo_backup; + GEOCLASS geoclass; + }; + + /* Known valid test nations and regions */ + struct geopair vietnam = {(WCHAR[]){'V','N',0}, 251}; + struct geopair brasil = {(WCHAR[]){'B','R',0}, 32}; + struct geopair west_europe = {(WCHAR[]){'1','5','5',0}, 10210824}; + struct geopair east_asia = {(WCHAR[]){'0','3','0',0}, 47600}; + + /* Invalid arguments */ + WCHAR too_long[] = {'w','e',' ','t','o','o',' ','l','o','n','g',0}; /* Names must have less than 3 chars */ + WCHAR too_short[] = {'P',0}; /* Names must be at least two characters */ + WCHAR wrong_un_m49[] = {'A','A','A',0}; /* UN M49 codes use numbers only */ + WCHAR wrong_iso_3166a2[] = {'1','2',0}; /* ISO 3166-1 alpha-2 country codes use the latin alphabet only */ + + const struct testsuit good_args[] = { + {"nation geoname", TRUE, ERROR_SUCCESS, vietnam, brasil, GEOCLASS_NATION}, + {"region geoname", TRUE, ERROR_SUCCESS, west_europe, east_asia, GEOCLASS_REGION} + }; + + const struct testsuit bad_args[] = { + {"too long geoname", FALSE, ERROR_INVALID_PARAMETER, {too_long}}, + {"too short geoname", FALSE, ERROR_INVALID_PARAMETER, {too_short}}, + {"invalid UN M49 code", FALSE, ERROR_INVALID_PARAMETER, {wrong_un_m49}}, + {"invalid ISO 3166 code", FALSE, ERROR_INVALID_PARAMETER, {wrong_iso_3166a2}} + }; + + const int original_count = pGetUserDefaultGeoName(NULL, 0); + WCHAR *const original_name = malloc(original_count * sizeof(WCHAR)); + const GEOID original_nation = GetUserGeoID(GEOCLASS_NATION); + const GEOID original_region = GetUserGeoID(GEOCLASS_REGION); + + /* Get current values before testing */ + if (original_name) + { + if (original_count != pGetUserDefaultGeoName(original_name, original_count)) + trace("Couldn't get original geo name; restoring is not possible.\n"); + } + else if (original_count) + trace("Couldn't allocate %lu bytes to store original name.\n", sizeof(WCHAR) * original_count); + + + for (int i = 0; i < ARRAY_SIZE(bad_args); i++) + { + BOOL status; + SetLastError(ERROR_SUCCESS); + + status = pSetUserGeoName(bad_args[i].geo.name); + ok((status == bad_args[i].exp_return) && (GetLastError() == bad_args[i].exp_error), + "Setting %s: Got ret=%d (expected %d) and lasterror=%d (expected %d).\n", + bad_args[i].stage, status, bad_args[i].exp_return, GetLastError(), bad_args[i].exp_error); + }; + + + for (int i = 0; i < ARRAY_SIZE(good_args); i++) + { + BOOL status; + const struct geopair *geo; + + if (winetest_strcmpW(original_name, good_args[i].geo.name)) + geo = &good_args[i].geo; + else + geo = &good_args[i].geo_backup; + + SetLastError(ERROR_SUCCESS); + + status = pSetUserGeoName(geo->name); + ok((status == good_args[i].exp_return) && (GetLastError() == good_args[i].exp_error), + "Setting geoname to %s: failed with ret=%d (expected %d) and lasterror=%d (expected %d).\n", + wine_dbgstr_w(geo->name), status, good_args[i].exp_return, GetLastError(), good_args[i].exp_error); + + if (status == good_args[i].exp_return) + { + const GEOID geoid = GetUserGeoID(good_args[i].geoclass); + + ok(geoid == geo->id, "%s (geoclass %d): Wrong GeoID for geoname %s: got %d (expected %d).\n", + good_args[i].stage, good_args[i].geoclass, wine_dbgstr_w(geo->name), geoid, geo->id); + } + } + + /* Best attempt at restoring original values */ + SetUserGeoID(original_region); + SetUserGeoID(original_nation); + pSetUserGeoName(original_name); + } + else win_skip("SetUserGeoName: procedure not implemented on this platform.\n"); + } +} + static void test_GetGeoInfo(void) { char buffA[20]; @@ -6058,6 +6373,10 @@ START_TEST(locale) test_SetThreadUILanguage(); test_NormalizeString(); test_SpecialCasing(); + test_GetUserGeoID(); + test_GetUserDefaultGeoName(); + test_SetUserGeoID(); + test_SetUserGeoName(); /* this requires collation table patch to make it MS compatible */ if (0) test_sorting(); }