From: Paul Gofman <pgofman(a)codeweavers.com> --- dlls/kernelbase/tests/path.c | 237 +++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c index d04bf35ad32..62a8f7e5b4f 100644 --- a/dlls/kernelbase/tests/path.c +++ b/dlls/kernelbase/tests/path.c @@ -53,6 +53,13 @@ HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size); HRESULT (WINAPI *pPathCchStripToRoot)(WCHAR *path, SIZE_T size); BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server); +BOOL (WINAPI *pPathIsRootA)(const char *path); +BOOL (WINAPI *pPathIsRootW)(const WCHAR *path); +BOOL (WINAPI *pPathStripToRootA)(char *path); +BOOL (WINAPI *pPathStripToRootW)(WCHAR *path); +BOOL (WINAPI *pPathRemoveFileSpecA)(char *path); +BOOL (WINAPI *pPathRemoveFileSpecW)(WCHAR *path); + struct alloccanonicalize_test { const CHAR *path_in; @@ -2352,6 +2359,228 @@ static void test_PathIsUNCEx(void) } } +static void test_path_manipulation(void) +{ + static const struct + { + const char *path; + BOOL is_root; + BOOL stript_to_root_ret; + HRESULT cch_strip_to_root_hr; + const char *strip_to_root; + BOOL remove_file_ret; + const char *remove_file; + BOOL aw_differ, w_version; + } + tests[] = + { + {"Q:\\", TRUE, TRUE, S_FALSE, "Q:\\", FALSE, "Q:\\"}, + {"Q:/", FALSE, TRUE, S_OK, "Q:", TRUE, "Q:"}, + {"Q:", FALSE, TRUE, S_FALSE, "Q:", FALSE, "Q:"}, + {"|:", FALSE, FALSE, E_INVALIDARG, "", TRUE, ""}, + {"Q:\\\\", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\"}, + {"Q:\\\\test1", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\"}, + {"Q:\\test1\\test2", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1"}, + {"Q:\\test1\\\\test2", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1"}, + {"Q:\\test1\\\\\\test2", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1\\"}, + {"Q:\\test1\\test2\\", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1\\test2"}, + {"Q:\\test1\\\\test2\\", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1\\\\test2"}, + {"Q:\\test1\\test2\\\\", FALSE, TRUE, S_OK, "Q:\\", TRUE, "Q:\\test1\\test2"}, + {"Q:/test1/test2", FALSE, TRUE, S_OK, "Q:", TRUE, "Q:"}, + {"Q:/test1\\test2", FALSE, TRUE, S_OK, "Q:", TRUE, "Q:/test1"}, + {"0:/test1/test2", FALSE, FALSE, E_INVALIDARG, "", TRUE, ""}, + {"test", FALSE, FALSE, E_INVALIDARG, "", TRUE, ""}, + {"\\\\?\\Q:\\", FALSE, FALSE, S_OK, "", TRUE, "\\\\?\\Q:", TRUE, FALSE}, + {"\\\\?\\Q:\\", TRUE, TRUE, S_FALSE, "\\\\?\\Q:\\", FALSE, "\\\\?\\Q:\\", TRUE, TRUE}, + {"\\\\?\\Q:\\a", FALSE, TRUE, S_OK, "\\\\?\\Q:\\", TRUE, "\\\\?\\Q:\\", TRUE, TRUE}, + {"\\\\?\\Q:\\\\", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\Q:", TRUE, FALSE}, + {"\\\\?\\Q:\\\\", FALSE, TRUE, S_OK, "\\\\?\\Q:\\", TRUE, "\\\\?\\Q:\\", TRUE, TRUE}, + {"\\\\?\\Q:", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?", TRUE, FALSE}, + {"\\\\?\\Q:", FALSE, TRUE, S_FALSE, "\\\\?\\Q:", FALSE, "\\\\?\\Q:", TRUE, TRUE}, + {"\\\\?\\aa\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?\\aa"}, + {"\\\\?\\aa", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?"}, + {"\\\\.\\Q:\\", FALSE, TRUE, S_OK, "\\\\.\\Q:", TRUE, "\\\\.\\Q:"}, + {"\\\\.\\Q:", TRUE, TRUE, S_FALSE, "\\\\.\\Q:", TRUE, "\\\\."}, + {"\\\\.\\", FALSE, TRUE, S_OK, "\\\\.", TRUE, "\\\\."}, + {"\\\\?\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?"}, + {"\\\\?\\\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?"}, + {"?", FALSE, FALSE, E_INVALIDARG, "", TRUE, ""}, + {"\\?", FALSE, TRUE, S_OK, "\\", TRUE, "\\"}, + {"\\\\?", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\"}, + {"\\\\*", TRUE, TRUE, S_FALSE, "\\\\*", TRUE, "\\\\"}, + {"\\\\.", TRUE, TRUE, S_FALSE, "\\\\.", TRUE, "\\\\"}, + {"\\\\\\.", TRUE, TRUE, S_FALSE, "\\\\\\.", TRUE, "\\\\\\"}, + {"\\\\\\a", TRUE, TRUE, S_FALSE, "\\\\\\a", TRUE, "\\\\\\"}, + {"\\\\\\\\.", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\"}, + {"\\\\!", TRUE, TRUE, S_FALSE, "\\\\!", TRUE, "\\\\"}, + {"\\\\|", TRUE, TRUE, S_FALSE, "\\\\|", TRUE, "\\\\"}, + {"\\\\a", TRUE, TRUE, S_FALSE, "\\\\a", TRUE, "\\\\"}, + {"\\\\a\\", FALSE, TRUE, S_OK, "\\\\a", TRUE, "\\\\a"}, + {"\\\\a\\Q:\\", FALSE, TRUE, S_OK, "\\\\a\\Q:", TRUE, "\\\\a\\Q:"}, + {"\\\\a\\Q:", TRUE, TRUE, S_FALSE, "\\\\a\\Q:", TRUE, "\\\\a"}, + {"\\\\aa\\Q:\\", FALSE, TRUE, S_OK, "\\\\aa\\Q:", TRUE, "\\\\aa\\Q:"}, + {"\\\\aa\\Q:", TRUE, TRUE, S_FALSE, "\\\\aa\\Q:", TRUE, "\\\\aa"}, + {"\\\\aa", TRUE, TRUE, S_FALSE, "\\\\aa", TRUE, "\\\\"}, + {"\\\\aa\\", FALSE, TRUE, S_OK, "\\\\aa", TRUE, "\\\\aa"}, + {"\\\\aa\\b", TRUE, TRUE, S_FALSE, "\\\\aa\\b", TRUE, "\\\\aa"}, + {"\\\\aa\\|", TRUE, TRUE, S_FALSE, "\\\\aa\\|", TRUE, "\\\\aa"}, + {"\\\\aa\\b\\c", FALSE, TRUE, S_OK, "\\\\aa\\b", TRUE, "\\\\aa\\b"}, + {"\\\\Q:", TRUE, TRUE, S_FALSE, "\\\\Q:", FALSE, "\\\\Q:"}, + {"\\\\\\Q:", TRUE, TRUE, S_FALSE, "\\\\\\Q:", TRUE, "\\\\\\"}, + {"\\\\Q:\\", FALSE, TRUE, S_OK, "\\\\Q:", TRUE, "\\\\Q:"}, + {"\\\\?Q:\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?Q:"}, + {"\\??\\Q:\\", FALSE, TRUE, S_OK, "\\", TRUE, "\\??\\Q:"}, + {"\\??\\", FALSE, TRUE, S_OK, "\\", TRUE, "\\??"}, + {"\\\\o\\Q:\\aaa", FALSE, TRUE, S_OK, "\\\\o\\Q:", TRUE, "\\\\o\\Q:"}, + {"||||Q:\\aaa", FALSE, FALSE, E_INVALIDARG, "", TRUE, "||||Q:"}, + {"\\\\\\\\Q:\\", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\\\\\Q:"}, + {"\\\\\\\\Q:", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\"}, + {"\\\\", TRUE, TRUE, S_FALSE, "\\\\", FALSE, "\\\\"}, + {"\\\\\\", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\"}, + {"\\\\\\\\", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\"}, + {"\\\\\\\\\\", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\\\"}, + {"\\\\\\\\\\\\", FALSE, TRUE, S_OK, "\\\\", TRUE, "\\\\\\\\"}, + {"\\", TRUE, TRUE, S_FALSE, "\\", FALSE, "\\"}, + {"\\a", FALSE, TRUE, S_OK, "\\", TRUE, "\\"}, + {"\\a\\b", FALSE, TRUE, S_OK, "\\", TRUE, "\\a"}, + {"\\\\a", TRUE, TRUE, S_FALSE, "\\\\a", TRUE, "\\\\"}, + {"\\\\a\\b", TRUE, TRUE, S_FALSE, "\\\\a\\b", TRUE, "\\\\a"}, + {"\\\\a\\\\b", FALSE, TRUE, S_OK, "\\\\a", TRUE, "\\\\a"}, + {"\\\\a\\b\\", FALSE, TRUE, S_OK, "\\\\a\\b", TRUE, "\\\\a\\b"}, + {"\\\\a\\b\\c", FALSE, TRUE, S_OK, "\\\\a\\b", TRUE, "\\\\a\\b"}, + {"", FALSE, FALSE, E_INVALIDARG, "", FALSE, ""}, + {"\\\\Q:\\", FALSE, TRUE, S_OK, "\\\\Q:", TRUE, "\\\\Q:"}, + {"\\Q:\\", FALSE, TRUE, S_OK, "\\", TRUE, "\\Q:"}, + {"\\Q:", FALSE, TRUE, S_OK, "\\", TRUE, "\\"}, + {"\\\\?\\UNC\\", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\UNC", TRUE, FALSE}, + {"\\\\?\\UNC\\", TRUE, TRUE, S_FALSE, "\\\\?\\UNC\\", TRUE, "\\\\?\\UNC", TRUE, TRUE}, + {"\\\\?\\UNC\\a", FALSE, FALSE, S_OK, "", TRUE, "\\\\?\\UNC", TRUE, FALSE}, + {"\\\\?\\UNC\\a", TRUE, TRUE, S_FALSE, "\\\\?\\UNC\\a", TRUE, "\\\\?\\UNC", TRUE, TRUE}, + {"\\\\?\\UNC\\a\\", FALSE, FALSE, S_OK, "", TRUE, "\\\\?\\UNC\\a", TRUE, FALSE}, + {"\\\\?\\UNC\\a\\", FALSE, TRUE, S_OK, "\\\\?\\UNC\\a", TRUE, "\\\\?\\UNC\\a", TRUE, TRUE}, + {"\\\\?\\UNC\\a\\b", FALSE, FALSE, S_OK, "", TRUE, "\\\\?\\UNC\\a", TRUE, FALSE}, + {"\\\\?\\UNC\\a\\b", TRUE, TRUE, S_FALSE, "\\\\?\\UNC\\a\\b", TRUE, "\\\\?\\UNC\\a", TRUE, TRUE}, + {"\\\\?\\UNC\\a\\b\\c", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\UNC\\a\\b", TRUE, FALSE}, + {"\\\\?\\UNC\\a\\b\\c", FALSE, TRUE, S_OK, "\\\\?\\UNC\\a\\b", TRUE, "\\\\?\\UNC\\a\\b", TRUE, TRUE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?", TRUE, FALSE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", FALSE, TRUE, S_FALSE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", FALSE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", TRUE, TRUE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", TRUE, FALSE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, TRUE, S_FALSE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", FALSE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, TRUE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\\\", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", TRUE, FALSE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\\\", FALSE, TRUE, S_OK, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, TRUE}, + {"\\\\?\\Volume{zaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?\\Volume{zaaaaaaa-bbbb-cccc-dddd-ffffffffffff}"}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\a", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}", TRUE, FALSE}, + {"\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\a", FALSE, TRUE, S_OK, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, "\\\\?\\Volume{aaaaaaaa-bbbb-cccc-dddd-ffffffffffff}\\", TRUE, TRUE}, + {"\\\\?\\TST\\", FALSE, FALSE, E_INVALIDARG, "", TRUE, "\\\\?\\TST"}, + {"\\\\?\\UNC\\Q:\\", FALSE, FALSE, S_FALSE, "", TRUE, "\\\\?\\UNC\\Q:", TRUE, FALSE}, + {"\\\\?\\UNC\\Q:\\", FALSE, TRUE, S_OK, "\\\\?\\UNC\\Q:", TRUE, "\\\\?\\UNC\\Q:", TRUE, TRUE}, + {"\\Device\\Harddiskvolume1", FALSE, TRUE, S_OK, "\\", TRUE, "\\Device"}, + {"\\Device\\Harddiskvolume1\\", FALSE, TRUE, S_OK, "\\", TRUE, "\\Device\\Harddiskvolume1"}, + }; + + WCHAR pathW[MAX_PATH], expectedW[MAX_PATH]; + unsigned int i, expected_len; + const WCHAR *end_pfx, *ptr; + HRESULT hr, expected_hr; + char path[MAX_PATH]; + BOOL ret; + + if (!pPathCchStripToRoot || !pPathCchSkipRoot || !pPathCchRemoveFileSpec || !pPathCchIsRoot) + { + win_skip("Functions are not available.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("%u (%s)", i, debugstr_a(tests[i].path)); + + strcpy(path, tests[i].path); + + if (!tests[i].aw_differ || !tests[i].w_version) + { + ret = pPathIsRootA(path); + ok(ret == tests[i].is_root, "PathIsRootA got %d, expected %d.\n", ret, tests[i].is_root); + ret = pPathStripToRootA(path); + ok(ret == tests[i].stript_to_root_ret, "PathStripToRootA got %d, expected %d.\n", ret, tests[i].stript_to_root_ret); + ok(!strcmp(path, tests[i].strip_to_root), "PathStripToRootA got %s, expected %s.\n", debugstr_a(path), debugstr_a(tests[i].strip_to_root)); + strcpy(path, tests[i].path); + ret = pPathRemoveFileSpecA(path); + ok(ret == tests[i].remove_file_ret, "PathRemoveFileSpecA got %d, expected %d.\n", ret, tests[i].remove_file_ret); + ok(!strcmp(path, tests[i].remove_file), "PathRemoveFileSpecA got %s, expected %s.\n", debugstr_a(path), debugstr_a(tests[i].remove_file)); + } + + if (!tests[i].aw_differ || tests[i].w_version) + { + MultiByteToWideChar(CP_ACP, 0, tests[i].path, -1, pathW, MAX_PATH); + ret = pPathIsRootW(pathW); + ok(ret == tests[i].is_root, "PathIsRootW got %d, expected %d.\n", ret, tests[i].is_root); + ret = pPathCchIsRoot(pathW); + ok(ret == tests[i].is_root, "pPathCchIsRoot got %d, expected %d.\n", ret, tests[i].is_root); + + ret = pPathStripToRootW(pathW); + MultiByteToWideChar(CP_ACP, 0, tests[i].strip_to_root, -1, expectedW, MAX_PATH); + ok(ret == tests[i].stript_to_root_ret, "PathStripToRootW got %d, expected %d.\n", ret, tests[i].stript_to_root_ret); + ok(!wcscmp(pathW, expectedW), "PathStripToRootW got %s, expected %s.\n", debugstr_w(pathW), debugstr_w(expectedW)); + + MultiByteToWideChar(CP_ACP, 0, tests[i].path, -1, pathW, MAX_PATH); + hr = pPathCchStripToRoot(pathW, ARRAY_SIZE(pathW)); + ok(hr == tests[i].cch_strip_to_root_hr, "PathCchStripToRoot got hr %#lx, expected %#lx.\n", hr, tests[i].cch_strip_to_root_hr); + ok(!wcscmp(pathW, expectedW), "PathCchStripToRoot got %s, expected %s.\n", debugstr_w(pathW), debugstr_w(expectedW)); + + MultiByteToWideChar(CP_ACP, 0, tests[i].path, -1, pathW, MAX_PATH); + end_pfx = NULL; + hr = pPathCchSkipRoot(pathW, &end_pfx); + expected_hr = SUCCEEDED(tests[i].cch_strip_to_root_hr) ? S_OK : tests[i].cch_strip_to_root_hr; + ok(hr == expected_hr, "PathCchSkipRoot got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + { + expected_len = wcslen(expectedW); + if (end_pfx && end_pfx > pathW/* && end_pfx[-1] == '\\'*/ && pathW[expected_len] == '\\' + && (!wcsnicmp(pathW, L"\\\\?\\UNC\\", 8 ) || (pathW[0] == '\\' && pathW[1] == '\\' && pathW[2] && pathW[2] != '?'))) + { + ok(end_pfx[-1] == '\\', "PathCchSkipRoot missing trailing backslash (end_pfx %s).\n", debugstr_w(end_pfx)); + end_pfx--; + } + ok(expected_len == end_pfx - pathW, "PathCchSkipRoot got %s, expected %s.\n", + debugstr_wn(pathW, end_pfx - pathW), debugstr_wn(pathW, expected_len)); + } + MultiByteToWideChar(CP_ACP, 0, tests[i].path, -1, pathW, MAX_PATH); + if (FAILED(hr)) + expected_hr = *pathW ? S_OK : S_FALSE; + else + expected_hr = *end_pfx ? S_OK : S_FALSE; + wcscpy(expectedW, pathW); + if (expected_hr != S_FALSE) + { + if (!end_pfx) + end_pfx = pathW; + if ((ptr = wcsrchr(end_pfx, '\\'))) + { + if (ptr > end_pfx && ptr[-1] == '\\' && ptr[1] != '?') + --ptr; + expectedW[ptr - pathW] = 0; + } + else + { + expectedW[end_pfx - pathW] = 0; + } + } + hr = pPathCchRemoveFileSpec(pathW, ARRAY_SIZE(pathW)); + ok(hr == expected_hr, "PathCchRemoveFileSpec got hr %#lx, expected %#lx.\n", hr, expected_hr); + ok(!wcscmp(pathW, expectedW), "PathCchRemoveFileSpec got %s, expected %s, end_pfx %s.\n", debugstr_w(pathW), debugstr_w(expectedW), debugstr_w(end_pfx)); + + MultiByteToWideChar(CP_ACP, 0, tests[i].path, -1, pathW, MAX_PATH); + ret = pPathRemoveFileSpecW(pathW); + MultiByteToWideChar(CP_ACP, 0, tests[i].remove_file, -1, expectedW, MAX_PATH); + ok(ret == tests[i].remove_file_ret, "PathRemoveFileSpecW got %d, expected %d.\n", ret, tests[i].remove_file_ret); + ok(!wcscmp(pathW, expectedW), "PathRemoveFileSpecW got %s, expected %s.\n", debugstr_w(pathW), debugstr_w(expectedW)); + } + + winetest_pop_context(); + } +} + static void test_actctx(void) { ACTCTX_SECTION_KEYED_DATA data = { sizeof(data) }; @@ -2399,6 +2628,13 @@ START_TEST(path) pPathCchStripToRoot = (void *)GetProcAddress(hmod, "PathCchStripToRoot"); pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx"); + pPathIsRootA = (void *)GetProcAddress(hmod, "PathIsRootA"); + pPathIsRootW = (void *)GetProcAddress(hmod, "PathIsRootW"); + pPathStripToRootA = (void *)GetProcAddress(hmod, "PathStripToRootA"); + pPathStripToRootW = (void *)GetProcAddress(hmod, "PathStripToRootW"); + pPathRemoveFileSpecA = (void *)GetProcAddress(hmod, "PathRemoveFileSpecA"); + pPathRemoveFileSpecW = (void *)GetProcAddress(hmod, "PathRemoveFileSpecW"); + test_PathAllocCanonicalize(); test_PathAllocCombine(); test_PathCchAddBackslash(); @@ -2421,5 +2657,6 @@ START_TEST(path) test_PathCchStripPrefix(); test_PathCchStripToRoot(); test_PathIsUNCEx(); + test_path_manipulation(); test_actctx(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6318