/* Unit test suite for Path functions * * Copyright 2002 Matthew Mastracci * * 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 "wine/test.h" #include "windef.h" #include "winbase.h" #include "winreg.h" #include "shlwapi.h" #include "wininet.h" static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD); static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD); static LPWSTR (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR); static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD); static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD); static HRESULT (WINAPI *pPathCreateFromUrlAlloc)(LPCWSTR, LPWSTR*, DWORD); static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR); static BOOL (WINAPI *pPathUnExpandEnvStringsA)(LPCSTR, LPSTR, UINT); static BOOL (WINAPI *pPathUnExpandEnvStringsW)(LPCWSTR, LPWSTR, UINT); /* ################ */ static const struct { const char *url; const char *path; DWORD ret, todo; } TEST_PATHFROMURL[] = { /* 0 leading slash */ {"file:c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:c|/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK, 0}, {"file:c:foo/bar", "c:foo\\bar", S_OK, 0}, {"file:c|foo/bar", "c:foo\\bar", S_OK, 0}, {"file:c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0}, {"file:foo%20ba%2fr", "foo ba/r", S_OK, 0}, {"file:foo/bar/", "foo\\bar\\", S_OK, 0}, /* 1 leading (back)slash */ {"file:/c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:\\c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:/c|/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:/cx|/foo/bar", "\\cx|\\foo\\bar", S_OK, 0}, {"file:/c:foo/bar", "c:foo\\bar", S_OK, 0}, {"file:/c|foo/bar", "c:foo\\bar", S_OK, 0}, {"file:/c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0}, {"file:/foo%20ba%2fr", "\\foo ba/r", S_OK, 0}, {"file:/foo/bar/", "\\foo\\bar\\", S_OK, 0}, /* 2 leading (back)slashes */ {"file://c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK, 0}, {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK, 0}, {"file://cx|/foo/bar", "\\\\cx|\\foo\\bar", S_OK, 0}, {"file://c:foo/bar", "c:foo\\bar", S_OK, 0}, {"file://c|foo/bar", "c:foo\\bar", S_OK, 0}, {"file://c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0}, {"file://c%3a/foo/../bar", "\\\\c:\\foo\\..\\bar", S_OK, 0}, {"file://c%7c/foo/../bar", "\\\\c|\\foo\\..\\bar", S_OK, 0}, {"file://foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0}, {"file://localhost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file://localhost/c:/foo%20ba%5Cr", "c:\\foo ba\\r", S_OK, 0}, {"file://LocalHost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:\\\\localhost\\c:\\foo\\bar", "c:\\foo\\bar", S_OK, 0}, {"file://incomplete", "\\\\incomplete", S_OK, 0}, /* 3 leading (back)slashes (omitting hostname) */ {"file:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"File:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:///c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0}, {"file:///foo%20ba%2fr", "\\foo ba/r", S_OK, 0}, {"file:///foo/bar/", "\\foo\\bar\\", S_OK, 0}, {"file:///localhost/c:/foo/bar", "\\localhost\\c:\\foo\\bar", S_OK, 0}, /* 4 leading (back)slashes */ {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK, 0}, {"file:////c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0}, {"file:////foo%20ba%2fr", "\\\\foo%20ba%2fr", S_OK, 0}, /* 5 and more leading (back)slashes */ {"file://///c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0}, {"file://///c:/foo%20ba%2fr", "\\\\c:\\foo ba/r", S_OK, 0}, {"file://///foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0}, {"file://////c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0}, /* Leading (back)slashes cannot be escaped */ {"file:%2f%2flocalhost%2fc:/foo/bar", "//localhost/c:\\foo\\bar", S_OK, 0}, {"file:%5C%5Clocalhost%5Cc:/foo/bar", "\\\\localhost\\c:\\foo\\bar", S_OK, 0}, /* Hostname handling */ {"file://l%6fcalhost/c:/foo/bar", "\\\\localhostc:\\foo\\bar", S_OK, 0}, {"file://localhost:80/c:/foo/bar", "\\\\localhost:80c:\\foo\\bar", S_OK, 0}, {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK, 0}, {"file://host//c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0}, {"file://host/\\c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0}, {"file://host/c:foo/bar", "\\\\hostc:foo\\bar", S_OK, 0}, {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK, 0}, {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK, 0}, {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK, 0}, {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK, 0}, {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK, 0}, {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK, 0}, {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK, 0}, /* Not file URLs */ {"c:\\foo\\bar", NULL, E_INVALIDARG, 0}, {"foo/bar", NULL, E_INVALIDARG, 0}, {"http://foo/bar", NULL, E_INVALIDARG, 0}, }; static struct { const char *path; BOOL expect; } TEST_PATH_IS_URL[] = { {"http://foo/bar", TRUE}, {"c:\\foo\\bar", FALSE}, {"c:/foo/bar", FALSE}, {"foo://foo/bar", TRUE}, {"foo\\bar", FALSE}, {"foo.bar", FALSE}, {"bogusscheme:", TRUE}, {"http:partial", TRUE}, {"www.winehq.org", FALSE}, /* More examples that the user might enter as the browser start page */ {"winehq.org", FALSE}, {"ftp.winehq.org", FALSE}, {"http://winehq.org", TRUE}, {"http://www.winehq.org", TRUE}, {"https://winehq.org", TRUE}, {"https://www.winehq.org", TRUE}, {"ftp://winehq.org", TRUE}, {"ftp://ftp.winehq.org", TRUE}, {"file://does_not_exist.txt", TRUE}, {"about:blank", TRUE}, {"about:home", TRUE}, {"about:mozilla", TRUE}, /* scheme is case independent */ {"HTTP://www.winehq.org", TRUE}, /* a space at the start is not allowed */ {" http://www.winehq.org", FALSE}, {"", FALSE}, {NULL, FALSE} }; static const struct { const char *path; const char *result; } TEST_PATH_UNQUOTE_SPACES[] = { { "abcdef", "abcdef" }, { "\"abcdef\"", "abcdef" }, { "\"abcdef", "\"abcdef" }, { "abcdef\"", "abcdef\"" }, { "\"\"abcdef\"\"", "\"abcdef\"" }, { "abc\"def", "abc\"def" }, { "\"abc\"def", "\"abc\"def" }, { "\"abc\"def\"", "abc\"def" }, { "\'abcdef\'", "\'abcdef\'" }, { "\"\"", "" }, { "\"", "" } }; /* ################ */ static LPWSTR GetWideString(const char* szString) { LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH); return wszString; } static void FreeWideString(LPWSTR wszString) { HeapFree(GetProcessHeap(), 0, wszString); } static LPSTR strdupA(LPCSTR p) { LPSTR ret; DWORD len = (strlen(p) + 1); ret = HeapAlloc(GetProcessHeap(), 0, len); memcpy(ret, p, len); return ret; } /* ################ */ static void test_PathSearchAndQualify(void) { WCHAR path1[] = {'c',':','\\','f','o','o',0}; WCHAR expect1[] = {'c',':','\\','f','o','o',0}; WCHAR path2[] = {'c',':','f','o','o',0}; WCHAR c_drive[] = {'c',':',0}; WCHAR foo[] = {'f','o','o',0}; WCHAR path3[] = {'\\','f','o','o',0}; WCHAR winini[] = {'w','i','n','.','i','n','i',0}; WCHAR out[MAX_PATH]; WCHAR cur_dir[MAX_PATH]; WCHAR dot[] = {'.',0}; /* c:\foo */ ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0, "PathSearchAndQualify rets 0\n"); ok(!lstrcmpiW(out, expect1), "strings don't match\n"); /* c:foo */ ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0, "PathSearchAndQualify rets 0\n"); GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL); PathAddBackslashW(cur_dir); lstrcatW(cur_dir, foo); ok(!lstrcmpiW(out, cur_dir), "strings don't match\n"); /* foo */ ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0, "PathSearchAndQualify rets 0\n"); GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL); PathAddBackslashW(cur_dir); lstrcatW(cur_dir, foo); ok(!lstrcmpiW(out, cur_dir), "strings don't match\n"); /* \foo */ ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0, "PathSearchAndQualify rets 0\n"); GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL); lstrcpyW(cur_dir + 2, path3); ok(!lstrcmpiW(out, cur_dir), "strings don't match\n"); /* win.ini */ ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0, "PathSearchAndQualify rets 0\n"); if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL)) GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL); ok(!lstrcmpiW(out, cur_dir), "strings don't match\n"); } static void test_PathCreateFromUrl(void) { size_t i; char ret_path[INTERNET_MAX_URL_LENGTH]; DWORD len, len2, ret; WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH]; WCHAR *pathW, *urlW; if (!pPathCreateFromUrlA) { win_skip("PathCreateFromUrlA not found\n"); return; } /* Won't say how much is needed without a buffer */ len = 0xdeca; ret = pPathCreateFromUrlA("file://foo", NULL, &len, 0); ok(ret == E_INVALIDARG, "got 0x%08x expected E_INVALIDARG\n", ret); ok(len == 0xdeca, "got %x expected 0xdeca\n", len); /* Test the decoding itself */ for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) { len = INTERNET_MAX_URL_LENGTH; ret = pPathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0); if (!(TEST_PATHFROMURL[i].todo & 0x1)) ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url); else todo_wine ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url); if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) { if(!(TEST_PATHFROMURL[i].todo & 0x2)) { ok(!lstrcmpiA(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url); ok(len == strlen(ret_path), "ret len %d from url %s\n", len, TEST_PATHFROMURL[i].url); } else todo_wine /* Wrong string, don't bother checking the length */ ok(!lstrcmpiA(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url); } if (pPathCreateFromUrlW) { len = INTERNET_MAX_URL_LENGTH; pathW = GetWideString(TEST_PATHFROMURL[i].path); urlW = GetWideString(TEST_PATHFROMURL[i].url); ret = pPathCreateFromUrlW(urlW, ret_pathW, &len, 0); WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),NULL,NULL); if (!(TEST_PATHFROMURL[i].todo & 0x1)) ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url); else todo_wine ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url); if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) { if(!(TEST_PATHFROMURL[i].todo & 0x2)) { ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url); ok(len == lstrlenW(ret_pathW), "ret len %d from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url); } else todo_wine /* Wrong string, don't bother checking the length */ ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url); } if (SUCCEEDED(ret)) { /* Check what happens if the buffer is too small */ len2 = 2; ret = pPathCreateFromUrlW(urlW, ret_pathW, &len2, 0); ok(ret == E_POINTER, "ret %08x, expected E_POINTER from url %s\n", ret, TEST_PATHFROMURL[i].url); if(!(TEST_PATHFROMURL[i].todo & 0x4)) ok(len2 == len + 1, "got len = %d expected %d from url %s\n", len2, len + 1, TEST_PATHFROMURL[i].url); else todo_wine ok(len2 == len + 1, "got len = %d expected %d from url %s\n", len2, len + 1, TEST_PATHFROMURL[i].url); } FreeWideString(urlW); FreeWideString(pathW); } } if (pPathCreateFromUrlAlloc) { static const WCHAR fileW[] = {'f','i','l','e',':','/','/','f','o','o',0}; static const WCHAR fooW[] = {'\\','\\','f','o','o',0}; pathW = NULL; ret = pPathCreateFromUrlAlloc(fileW, &pathW, 0); ok(ret == S_OK, "got 0x%08x expected S_OK\n", ret); ok(lstrcmpiW(pathW, fooW) == 0, "got %s expected %s\n", wine_dbgstr_w(pathW), wine_dbgstr_w(fooW)); HeapFree(GetProcessHeap(), 0, pathW); } } static void test_PathIsUrl(void) { size_t i; BOOL ret; for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) { ret = PathIsURLA(TEST_PATH_IS_URL[i].path); ok(ret == TEST_PATH_IS_URL[i].expect, "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path, TEST_PATH_IS_URL[i].expect); } } static const DWORD SHELL_charclass[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000080, 0x00000100, 0x00000200, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000002, 0x00000100, 0x00000040, 0x00000100, 0x00000004, 0x00000000, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000010, 0x00000020, 0x00000000, 0x00000100, 0x00000000, 0x00000001, 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100, 0x00000008, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100, 0x00000000, 0x00000100, 0x00000100 }; static void test_PathIsValidCharA(void) { BOOL ret; unsigned int c; /* For whatever reason, PathIsValidCharA and PathAppendA share the same * ordinal number in some native versions. Check this to prevent a crash. */ if (!pPathIsValidCharA || pPathIsValidCharA == (void*)pPathAppendA) { win_skip("PathIsValidCharA isn't available\n"); return; } for (c = 0; c < 0x7f; c++) { ret = pPathIsValidCharA( c, ~0U ); ok ( ret || !SHELL_charclass[c], "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret ); } for (c = 0x7f; c <= 0xff; c++) { ret = pPathIsValidCharA( c, ~0U ); ok ( ret, "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret ); } } static void test_PathIsValidCharW(void) { BOOL ret; unsigned int c; if (!pPathIsValidCharW) { win_skip("PathIsValidCharW isn't available\n"); return; } for (c = 0; c < 0x7f; c++) { ret = pPathIsValidCharW( c, ~0U ); ok ( ret || !SHELL_charclass[c], "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret ); } for (c = 0x007f; c <= 0xffff; c++) { ret = pPathIsValidCharW( c, ~0U ); ok ( ret, "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret ); } } static void test_PathMakePretty(void) { char buff[MAX_PATH]; ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n"); buff[0] = '\0'; ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n"); strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT"); ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n"); ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0, "PathMakePretty: Long UC name not changed\n"); strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT"); ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n"); ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0, "PathMakePretty: Failed but modified path\n"); strcpy(buff, "TEST"); ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Short name failed\n"); ok (strcmp(buff, "Test") == 0, "PathMakePretty: 1st char lowercased %s\n", buff); } static void test_PathMatchSpec(void) { static const char file[] = "c:\\foo\\bar\\filename.ext"; static const char spec1[] = ".ext"; static const char spec2[] = "*.ext"; static const char spec3[] = "*.ext "; static const char spec4[] = " *.ext"; static const char spec5[] = "* .ext"; static const char spec6[] = "*. ext"; static const char spec7[] = "* . ext"; static const char spec8[] = "*.e?t"; static const char spec9[] = "filename.ext"; static const char spec10[] = "*bar\\filename.ext"; static const char spec11[] = " foo; *.ext"; static const char spec12[] = "*.ext;*.bar"; static const char spec13[] = "*bar*"; ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n"); ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n"); ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n"); ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n"); todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n"); todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n"); ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n"); ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n"); ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n"); ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n"); ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n"); ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n"); ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n"); } static void test_PathCombineW(void) { LPWSTR wszString, wszString2; WCHAR wbuf[MAX_PATH+1], wstr1[MAX_PATH] = {'C',':','\\',0}, wstr2[MAX_PATH]; static const WCHAR expout[] = {'C',':','\\','A','A',0}; int i; if (!pPathCombineW) { win_skip("PathCombineW isn't available\n"); return; } wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); /* NULL test */ wszString = pPathCombineW(NULL, NULL, NULL); ok (wszString == NULL, "Expected a NULL return\n"); /* Some NULL */ wszString2[0] = 'a'; wszString = pPathCombineW(wszString2, NULL, NULL); ok (wszString == NULL || broken(wszString[0] == 'a'), /* Win95 and some W2K */ "Expected a NULL return\n"); ok (wszString2[0] == 0 || broken(wszString2[0] == 'a'), /* Win95 and some W2K */ "Destination string not empty\n"); HeapFree(GetProcessHeap(), 0, wszString2); /* overflow test */ wstr2[0] = wstr2[1] = wstr2[2] = 'A'; for (i=3; i 0, "failed to get sysdir\n"); sysdrvA[0] = path[0]; strcpy(&sysdrvA[1], ":"); /* buffer size is not enough */ strcpy(buff, "xx"); SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsA(path, buff, 5); ok(!ret && GetLastError() == 0xdeadbeef, "got %d\n", ret); ok(buff[0] == 'x', "wrong return string %s\n", buff); /* buffer size is enough to hold variable name only */ strcpy(buff, "xx"); SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsA(path, buff, sizeof(sysrootA)); ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError()); ok(buff[0] == 'x', "wrong return string %s\n", buff); /* enough size */ buff[0] = 0; ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff)); ok(ret, "got %d\n", ret); ok(!strncmp(buff, sysrootA, sizeof(sysrootA)-1), "wrong return string %s\n", buff); /* expanded value occurs multiple times */ /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */ buff[0] = 0; strcpy(path, sysdrvA); strcat(path, sysdrvA); ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff)); ok(ret, "got %d\n", ret); /* expected string */ strcpy(path, sysdriveA); strcat(path, sysdrvA); ok(!strcmp(buff, path), "wrong unexpanded string %s, expected %s\n", buff, path); /* now with altered variable */ ret = GetEnvironmentVariableA("SystemDrive", envvarA, sizeof(envvarA)); ok(ret, "got %d\n", ret); ret = SetEnvironmentVariableA("SystemDrive", "WW"); ok(ret, "got %d\n", ret); /* variables are not cached */ strcpy(path, sysdrvA); strcat(path, sysdrvA); SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff)); ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError()); ret = SetEnvironmentVariableA("SystemDrive", envvarA); ok(ret, "got %d\n", ret); /* PathUnExpandEnvStringsW */ /* something that can't be represented with env var */ lstrcpyW(pathW, nonpathW); buffW[0] = 'x'; buffW[1] = 0; SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR)); ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError()); ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW)); len = GetSystemDirectoryW(pathW, MAX_PATH); ok(len > 0, "failed to get sysdir\n"); sysdrvW[0] = pathW[0]; sysdrvW[1] = ':'; sysdrvW[2] = 0; /* buffer size is not enough */ buffW[0] = 'x'; buffW[1] = 0; SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsW(pathW, buffW, 5); ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError()); ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW)); /* buffer size is enough to hold variable name only */ buffW[0] = 'x'; buffW[1] = 0; SetLastError(0xdeadbeef); ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(sysrootW)/sizeof(WCHAR)); ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError()); ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW)); /* enough size */ buffW[0] = 0; ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR)); ok(ret, "got %d\n", ret); ok(!memcmp(buffW, sysrootW, sizeof(sysrootW) - sizeof(WCHAR)), "wrong return string %s\n", wine_dbgstr_w(buffW)); /* expanded value occurs multiple times */ /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */ buffW[0] = 0; lstrcpyW(pathW, sysdrvW); lstrcatW(pathW, sysdrvW); ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buff)/sizeof(WCHAR)); ok(ret, "got %d\n", ret); /* expected string */ lstrcpyW(pathW, sysdriveW); lstrcatW(pathW, sysdrvW); ok(!lstrcmpW(buffW, pathW), "wrong unexpanded string %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(pathW)); } START_TEST(path) { HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll"); /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){ win_skip("Too old shlwapi version\n"); return; } pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA"); pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW"); pPathCreateFromUrlAlloc = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlAlloc"); pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW"); pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455); pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456); pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA"); pPathUnExpandEnvStringsA = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsA"); pPathUnExpandEnvStringsW = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsW"); test_PathSearchAndQualify(); test_PathCreateFromUrl(); test_PathIsUrl(); test_PathAddBackslash(); test_PathMakePretty(); test_PathMatchSpec(); test_PathIsValidCharA(); test_PathIsValidCharW(); test_PathCombineW(); test_PathCombineA(); test_PathAppendA(); test_PathCanonicalizeA(); test_PathFindExtensionA(); test_PathBuildRootA(); test_PathCommonPrefixA(); test_PathUnquoteSpaces(); test_PathGetDriveNumber(); test_PathUnExpandEnvStrings(); }