/* * Path tests for kernelbase.dll * * Copyright 2017 Michael Müller * Copyright 2018 Zhiyi Zhang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include "wine/test.h" HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size); HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining); HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags); HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension); HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size); HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); static const struct { const char *path1; const char *path2; const char *result; } combine_test[] = { /* normal paths */ {"C:\\", "a", "C:\\a" }, {"C:\\b", "..\\a", "C:\\a" }, {"C:", "a", "C:\\a" }, {"C:\\", ".", "C:\\" }, {"C:\\", "..", "C:\\" }, {"\\a", "b", "\\a\\b" }, /* normal UNC paths */ {"\\\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a" }, {"\\\\192.168.1.1\\test", "..", "\\\\192.168.1.1" }, /* NT paths */ {"\\\\?\\C:\\", "a", "C:\\a" }, {"\\\\?\\C:\\", "..", "C:\\" }, /* NT UNC path */ {"\\\\?\\UNC\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a" }, {"\\\\?\\UNC\\192.168.1.1\\test", "..", "\\\\192.168.1.1" }, }; static void test_PathCchCombineEx(void) { WCHAR expected[MAX_PATH] = {'C',':','\\','a',0}; WCHAR p1[MAX_PATH] = {'C',':','\\',0}; WCHAR p2[MAX_PATH] = {'a',0}; WCHAR output[MAX_PATH]; HRESULT hr; int i; if (!pPathCchCombineEx) { skip("PathCchCombineEx() is not available.\n"); return; } hr = pPathCchCombineEx(NULL, 2, p1, p2, 0); ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); memset(output, 0xff, sizeof(output)); hr = pPathCchCombineEx(output, 0, p1, p2, 0); ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); ok(output[0] == 0xffff, "Expected output buffer to be unchanged\n"); memset(output, 0xff, sizeof(output)); hr = pPathCchCombineEx(output, 1, p1, p2, 0); ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr); ok(output[0] == 0, "Expected output buffer to contain NULL string\n"); memset(output, 0xff, sizeof(output)); hr = pPathCchCombineEx(output, 4, p1, p2, 0); ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr); ok(output[0] == 0x0, "Expected output buffer to contain NULL string\n"); memset(output, 0xff, sizeof(output)); hr = pPathCchCombineEx(output, 5, p1, p2, 0); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(output, expected), "Combination of %s + %s returned %s, expected %s\n", wine_dbgstr_w(p1), wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected)); for (i = 0; i < ARRAY_SIZE(combine_test); i++) { MultiByteToWideChar(CP_ACP, 0, combine_test[i].path1, -1, p1, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, combine_test[i].path2, -1, p2, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, combine_test[i].result, -1, expected, MAX_PATH); hr = pPathCchCombineEx(output, MAX_PATH, p1, p2, 0); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(output, expected), "Combining %s with %s returned %s, expected %s\n", wine_dbgstr_w(p1), wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected)); } } struct addbackslash_test { const char *path; const char *result; HRESULT hr; SIZE_T size; SIZE_T remaining; }; static const struct addbackslash_test addbackslash_tests[] = { { "C:", "C:\\", S_OK, MAX_PATH, MAX_PATH - 3 }, { "a.txt", "a.txt\\", S_OK, MAX_PATH, MAX_PATH - 6 }, { "a/b", "a/b\\", S_OK, MAX_PATH, MAX_PATH - 4 }, { "C:\\", "C:\\", S_FALSE, MAX_PATH, MAX_PATH - 3 }, { "C:\\", "C:\\", S_FALSE, 4, 1 }, { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 }, { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 1 }, { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 }, { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 0 }, { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 }, { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 }, }; static void test_PathCchAddBackslash(void) { WCHAR pathW[MAX_PATH]; unsigned int i; HRESULT hr; if (!pPathCchAddBackslash) { win_skip("PathCchAddBackslash() is not available.\n"); return; } pathW[0] = 0; hr = pPathCchAddBackslash(pathW, 0); ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); pathW[0] = 0; hr = pPathCchAddBackslash(pathW, 1); ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); pathW[0] = 0; hr = pPathCchAddBackslash(pathW, 2); ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); for (i = 0; i < ARRAY_SIZE(addbackslash_tests); i++) { const struct addbackslash_test *test = &addbackslash_tests[i]; char path[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchAddBackslash(pathW, test->size); ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, ARRAY_SIZE(path), NULL, NULL); ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path); } } static void test_PathCchAddBackslashEx(void) { WCHAR pathW[MAX_PATH]; SIZE_T remaining; unsigned int i; HRESULT hr; WCHAR *ptrW; if (!pPathCchAddBackslashEx) { win_skip("PathCchAddBackslashEx() is not available.\n"); return; } pathW[0] = 0; hr = pPathCchAddBackslashEx(pathW, 0, NULL, NULL); ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); pathW[0] = 0; ptrW = (void *)0xdeadbeef; remaining = 123; hr = pPathCchAddBackslashEx(pathW, 1, &ptrW, &remaining); ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); ok(ptrW == pathW, "Unexpected endptr %p.\n", ptrW); ok(remaining == 1, "Unexpected remaining size.\n"); pathW[0] = 0; hr = pPathCchAddBackslashEx(pathW, 2, NULL, NULL); ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); ok(pathW[0] == 0, "Unexpected path.\n"); for (i = 0; i < ARRAY_SIZE(addbackslash_tests); i++) { const struct addbackslash_test *test = &addbackslash_tests[i]; char path[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchAddBackslashEx(pathW, test->size, NULL, NULL); ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, ARRAY_SIZE(path), NULL, NULL); ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path); ptrW = (void *)0xdeadbeef; remaining = 123; MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchAddBackslashEx(pathW, test->size, &ptrW, &remaining); ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); if (SUCCEEDED(hr)) { ok(ptrW == (pathW + lstrlenW(pathW)), "%u: unexpected end pointer.\n", i); ok(remaining == test->remaining, "%u: unexpected remaining buffer length.\n", i); } else { ok(ptrW == NULL, "%u: unexpecred end pointer.\n", i); ok(remaining == 0, "%u: unexpected remaining buffer length.\n", i); } } } struct addextension_test { const CHAR *path; const CHAR *extension; const CHAR *expected; HRESULT hr; }; static const struct addextension_test addextension_tests[] = { /* Normal */ {"", ".exe", ".exe", S_OK}, {"C:\\", "", "C:\\", S_OK}, {"C:", ".exe", "C:.exe", S_OK}, {"C:\\", ".exe", "C:\\.exe", S_OK}, {"\\", ".exe", "\\.exe", S_OK}, {"\\\\", ".exe", "\\\\.exe", S_OK}, {"\\\\?\\C:", ".exe", "\\\\?\\C:.exe", S_OK}, {"\\\\?\\C:\\", ".exe", "\\\\?\\C:\\.exe", S_OK}, {"\\\\?\\UNC\\", ".exe", "\\\\?\\UNC\\.exe", S_OK}, {"\\\\?\\UNC\\192.168.1.1\\", ".exe", "\\\\?\\UNC\\192.168.1.1\\.exe", S_OK}, {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", ".exe", "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\.exe", S_OK}, {"C:\\", "exe", "C:\\.exe", S_OK}, {"C:\\", ".", "C:\\", S_OK}, {"C:\\1.exe", ".txt", "C:\\1.exe", S_FALSE}, /* Extension contains invalid characters but valid for PathCchAddExtension */ {"C:\\", "./", "C:\\./", S_OK}, {"C:\\", ".?", "C:\\.?", S_OK}, {"C:\\", ".%", "C:\\.%", S_OK}, {"C:\\", ".*", "C:\\.*", S_OK}, {"C:\\", ".:", "C:\\.:", S_OK}, {"C:\\", ".|", "C:\\.|", S_OK}, {"C:\\", ".\"", "C:\\.\"", S_OK}, {"C:\\", ".<", "C:\\.<", S_OK}, {"C:\\", ".>", "C:\\.>", S_OK}, /* Invalid argument for extension */ {"C:\\", " exe", NULL, E_INVALIDARG}, {"C:\\", ". exe", NULL, E_INVALIDARG}, {"C:\\", " ", NULL, E_INVALIDARG}, {"C:\\", "\\", NULL, E_INVALIDARG}, {"C:\\", "..", NULL, E_INVALIDARG}, {"C:\\", ". ", NULL, E_INVALIDARG}, {"C:\\", ".\\", NULL, E_INVALIDARG}, {"C:\\", ".a.", NULL, E_INVALIDARG}, {"C:\\", ".a ", NULL, E_INVALIDARG}, {"C:\\", ".a\\", NULL, E_INVALIDARG}, {"C:\\1.exe", " ", NULL, E_INVALIDARG} }; static void test_PathCchAddExtension(void) { WCHAR pathW[PATHCCH_MAX_CCH + 1]; CHAR pathA[PATHCCH_MAX_CCH + 1]; WCHAR extensionW[MAX_PATH]; HRESULT hr; INT i; if (!pPathCchAddExtension) { win_skip("PathCchAddExtension() is not available.\n"); return; } /* Arguments check */ MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, pathW, ARRAY_SIZE(pathW)); MultiByteToWideChar(CP_ACP, 0, ".exe", -1, extensionW, ARRAY_SIZE(extensionW)); hr = pPathCchAddExtension(NULL, PATHCCH_MAX_CCH, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchAddExtension(pathW, 0, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, NULL); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); /* Path length check */ hr = pPathCchAddExtension(pathW, ARRAY_SIZE("C:\\.exe") - 1, extensionW); ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect result %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr); hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH + 1, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, extensionW); ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr); for (i = 0; i < ARRAY_SIZE(addextension_tests); i++) { const struct addextension_test *t = addextension_tests + i; MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); MultiByteToWideChar(CP_ACP, 0, t->extension, -1, extensionW, ARRAY_SIZE(extensionW)); hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, extensionW); ok(hr == t->hr, "path %s extension %s expect result %#x, got %#x\n", t->path, t->extension, t->hr, hr); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL); ok(!lstrcmpA(pathA, t->expected), "path %s extension %s expect output path %s, got %s\n", t->path, t->extension, t->expected, pathA); } } } struct findextension_test { const CHAR *path; INT extension_offset; }; static const struct findextension_test findextension_tests[] = { /* Normal */ {"1.exe", 1}, {"C:1.exe", 3}, {"C:\\1.exe", 4}, {"\\1.exe", 2}, {"\\\\1.exe", 3}, {"\\\\?\\C:1.exe", 7}, {"\\\\?\\C:\\1.exe", 8}, {"\\\\?\\UNC\\1.exe", 9}, {"\\\\?\\UNC\\192.168.1.1\\1.exe", 21}, {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe", 50}, /* Contains forward slash */ {"C:\\a/1.exe", 6}, {"/1.exe", 2}, {"//1.exe", 3}, {"C:\\a/b/1.exe", 8}, {"/a/1.exe", 4}, {"/a/1.exe", 4}, /* Malformed */ {"", 0}, {" ", 1}, {".", 0}, {"..", 1}, {"a", 1}, {"a.", 1}, {".a.b.", 4}, {"a. ", 3}, {"a.\\", 3}, {"\\\\?\\UNC\\192.168.1.1", 17}, {"\\\\?\\UNC\\192.168.1.1\\", 20}, {"\\\\?\\UNC\\192.168.1.1\\a", 21} }; static void test_PathCchFindExtension(void) { WCHAR pathW[PATHCCH_MAX_CCH + 1] = {0}; const WCHAR *extension; HRESULT hr; INT i; if (!pPathCchFindExtension) { win_skip("PathCchFindExtension() is not available.\n"); return; } /* Arguments check */ extension = (const WCHAR *)0xdeadbeef; hr = pPathCchFindExtension(NULL, PATHCCH_MAX_CCH, &extension); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); ok(extension == NULL, "Expect extension null, got %p\n", extension); extension = (const WCHAR *)0xdeadbeef; hr = pPathCchFindExtension(pathW, 0, &extension); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); ok(extension == NULL, "Expect extension null, got %p\n", extension); /* Crashed on Windows */ if (0) { hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, NULL); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); } /* Path length check */ /* size == PATHCCH_MAX_CCH + 1 */ MultiByteToWideChar(CP_ACP, 0, "C:\\1.exe", -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH + 1, &extension); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); /* Size == path length + 1*/ hr = pPathCchFindExtension(pathW, ARRAY_SIZE("C:\\1.exe"), &extension); ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr); ok(*extension == '.', "wrong extension value\n"); /* Size < path length + 1 */ extension = (const WCHAR *)0xdeadbeef; hr = pPathCchFindExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1, &extension); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); ok(extension == NULL, "Expect extension null, got %p\n", extension); /* Size == PATHCCH_MAX_CCH */ hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension); ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr); /* Path length + 1 > PATHCCH_MAX_CCH */ for (i = 0; i < ARRAY_SIZE(pathW) - 1; i++) pathW[i] = 'a'; pathW[PATHCCH_MAX_CCH] = 0; hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); /* Path length + 1 == PATHCCH_MAX_CCH */ pathW[PATHCCH_MAX_CCH - 1] = 0; hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension); ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr); for (i = 0; i < ARRAY_SIZE(findextension_tests); i++) { const struct findextension_test *t = findextension_tests + i; MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension); ok(hr == S_OK, "path %s expect result %#x, got %#x\n", t->path, S_OK, hr); if (SUCCEEDED(hr)) ok(extension - pathW == t->extension_offset, "path %s expect extension offset %d, got %ld\n", t->path, t->extension_offset, (UINT_PTR)(extension - pathW)); } } struct removeextension_test { const CHAR *path; const CHAR *expected; HRESULT hr; }; static const struct removeextension_test removeextension_tests[] = { {"1.exe", "1", S_OK}, {"C:1.exe", "C:1", S_OK}, {"C:\\1.exe", "C:\\1", S_OK}, {"\\1.exe", "\\1", S_OK}, {"\\\\1.exe", "\\\\1", S_OK}, {"\\\\?\\C:1.exe", "\\\\?\\C:1", S_OK}, {"\\\\?\\C:\\1.exe", "\\\\?\\C:\\1", S_OK}, {"\\\\?\\UNC\\1.exe", "\\\\?\\UNC\\1", S_OK}, {"\\\\?\\UNC\\192.168.1.1\\1.exe", "\\\\?\\UNC\\192.168.1.1\\1", S_OK}, {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe", "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1", S_OK}, /* Malformed */ {"", "", S_FALSE}, {" ", " ", S_FALSE}, {".", "", S_OK}, {"..", ".", S_OK}, {"a", "a", S_FALSE}, {"a.", "a", S_OK}, {".a.b.", ".a.b", S_OK}, {"a. ", "a. ", S_FALSE}, {"a.\\", "a.\\", S_FALSE}, {"\\\\?\\UNC\\192.168.1.1", "\\\\?\\UNC\\192.168.1", S_OK}, {"\\\\?\\UNC\\192.168.1.1\\", "\\\\?\\UNC\\192.168.1.1\\", S_FALSE}, {"\\\\?\\UNC\\192.168.1.1\\a", "\\\\?\\UNC\\192.168.1.1\\a", S_FALSE} }; static void test_PathCchRemoveExtension(void) { WCHAR pathW[PATHCCH_MAX_CCH] = {0}; CHAR pathA[PATHCCH_MAX_CCH]; HRESULT hr; INT i; if (!pPathCchRemoveExtension) { win_skip("PathCchRemoveExtension() is not available.\n"); return; } /* Arguments check */ hr = pPathCchRemoveExtension(NULL, PATHCCH_MAX_CCH); ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRemoveExtension(pathW, 0); ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRemoveExtension(pathW, PATHCCH_MAX_CCH + 1); ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRemoveExtension(pathW, PATHCCH_MAX_CCH); ok(hr == S_FALSE, "expect %#x, got %#x\n", S_FALSE, hr); /* Size < original path length + 1 */ MultiByteToWideChar(CP_ACP, 0, "C:\\1.exe", -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchRemoveExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1); ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); for (i = 0; i < ARRAY_SIZE(removeextension_tests); i++) { const struct removeextension_test *t = removeextension_tests + i; MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); hr = pPathCchRemoveExtension(pathW, ARRAY_SIZE(pathW)); ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL); ok(!lstrcmpA(pathA, t->expected), "path %s expect stripped path %s, got %s\n", t->path, t->expected, pathA); } } } struct renameextension_test { const CHAR *path; const CHAR *extension; const CHAR *expected; }; static const struct renameextension_test renameextension_tests[] = { {"1.exe", ".txt", "1.txt"}, {"C:1.exe", ".txt", "C:1.txt"}, {"C:\\1.exe", ".txt", "C:\\1.txt"}, {"\\1.exe", ".txt", "\\1.txt"}, {"\\\\1.exe", ".txt", "\\\\1.txt"}, {"\\\\?\\C:1.exe", ".txt", "\\\\?\\C:1.txt"}, {"\\\\?\\C:\\1.exe", ".txt", "\\\\?\\C:\\1.txt"}, {"\\\\?\\UNC\\1.exe", ".txt", "\\\\?\\UNC\\1.txt"}, {"\\\\?\\UNC\\192.168.1.1\\1.exe", ".txt", "\\\\?\\UNC\\192.168.1.1\\1.txt"}, {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe", ".txt", "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.txt"}, {"C:\\1.exe", "", "C:\\1"}, {"C:\\1.exe", "txt", "C:\\1.txt"} }; static void test_PathCchRenameExtension(void) { WCHAR pathW[PATHCCH_MAX_CCH + 1]; CHAR pathA[PATHCCH_MAX_CCH + 1]; WCHAR extensionW[MAX_PATH]; HRESULT hr; INT i; if (!pPathCchRenameExtension) { win_skip("PathCchRenameExtension() is not available.\n"); return; } /* Invalid arguments */ MultiByteToWideChar(CP_ACP, 0, "C:\\1.txt", -1, pathW, ARRAY_SIZE(pathW)); MultiByteToWideChar(CP_ACP, 0, ".exe", -1, extensionW, ARRAY_SIZE(extensionW)); hr = pPathCchRenameExtension(NULL, PATHCCH_MAX_CCH, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRenameExtension(pathW, 0, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, NULL); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); /* Path length */ hr = pPathCchRenameExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1, extensionW); ok(E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH + 1, extensionW); ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr); hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, extensionW); ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr); for (i = 0; i < ARRAY_SIZE(renameextension_tests); i++) { const struct renameextension_test *t = renameextension_tests + i; MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); MultiByteToWideChar(CP_ACP, 0, t->extension, -1, extensionW, ARRAY_SIZE(extensionW)); hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, extensionW); ok(hr == S_OK, "path %s extension %s expect result %#x, got %#x\n", t->path, t->extension, S_OK, hr); if (SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL); ok(!lstrcmpA(pathA, t->expected), "path %s extension %s expect output path %s, got %s\n", t->path, t->extension, t->expected, pathA); } } } START_TEST(path) { HMODULE hmod = LoadLibraryA("kernelbase.dll"); pPathCchCombineEx = (void *)GetProcAddress(hmod, "PathCchCombineEx"); pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash"); pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx"); pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension"); pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension"); pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension"); pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension"); test_PathCchCombineEx(); test_PathCchAddBackslash(); test_PathCchAddBackslashEx(); test_PathCchAddExtension(); test_PathCchFindExtension(); test_PathCchRemoveExtension(); test_PathCchRenameExtension(); }