[SHLWAPI_WINETEST] Sync with Wine 3.0. CORE-14225
[reactos.git] / modules / rostests / winetests / shlwapi / path.c
1 /* Unit test suite for Path functions
2 *
3 * Copyright 2002 Matthew Mastracci
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "precomp.h"
21
22 static BOOL (WINAPI *pPathIsValidCharA)(char,DWORD);
23 static BOOL (WINAPI *pPathIsValidCharW)(WCHAR,DWORD);
24 static LPWSTR (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR);
25 static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD);
26 static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD);
27 static HRESULT (WINAPI *pPathCreateFromUrlAlloc)(LPCWSTR, LPWSTR*, DWORD);
28 static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
29 static BOOL (WINAPI *pPathUnExpandEnvStringsA)(LPCSTR, LPSTR, UINT);
30 static BOOL (WINAPI *pPathUnExpandEnvStringsW)(LPCWSTR, LPWSTR, UINT);
31 static BOOL (WINAPI *pPathIsRelativeA)(LPCSTR);
32 static BOOL (WINAPI *pPathIsRelativeW)(LPCWSTR);
33
34 /* ################ */
35
36 static const struct {
37 const char *url;
38 const char *path;
39 DWORD ret, todo;
40 } TEST_PATHFROMURL[] = {
41 /* 0 leading slash */
42 {"file:c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
43 {"file:c|/foo/bar", "c:\\foo\\bar", S_OK, 0},
44 {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK, 0},
45 {"file:c:foo/bar", "c:foo\\bar", S_OK, 0},
46 {"file:c|foo/bar", "c:foo\\bar", S_OK, 0},
47 {"file:c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
48 {"file:foo%20ba%2fr", "foo ba/r", S_OK, 0},
49 {"file:foo/bar/", "foo\\bar\\", S_OK, 0},
50
51 /* 1 leading (back)slash */
52 {"file:/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
53 {"file:\\c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
54 {"file:/c|/foo/bar", "c:\\foo\\bar", S_OK, 0},
55 {"file:/cx|/foo/bar", "\\cx|\\foo\\bar", S_OK, 0},
56 {"file:/c:foo/bar", "c:foo\\bar", S_OK, 0},
57 {"file:/c|foo/bar", "c:foo\\bar", S_OK, 0},
58 {"file:/c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
59 {"file:/foo%20ba%2fr", "\\foo ba/r", S_OK, 0},
60 {"file:/foo/bar/", "\\foo\\bar\\", S_OK, 0},
61
62 /* 2 leading (back)slashes */
63 {"file://c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
64 {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK, 0},
65 {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK, 0},
66 {"file://cx|/foo/bar", "\\\\cx|\\foo\\bar", S_OK, 0},
67 {"file://c:foo/bar", "c:foo\\bar", S_OK, 0},
68 {"file://c|foo/bar", "c:foo\\bar", S_OK, 0},
69 {"file://c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0},
70 {"file://c%3a/foo/../bar", "\\\\c:\\foo\\..\\bar", S_OK, 0},
71 {"file://c%7c/foo/../bar", "\\\\c|\\foo\\..\\bar", S_OK, 0},
72 {"file://foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0},
73 {"file://localhost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
74 {"file://localhost/c:/foo%20ba%5Cr", "c:\\foo ba\\r", S_OK, 0},
75 {"file://LocalHost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
76 {"file:\\\\localhost\\c:\\foo\\bar", "c:\\foo\\bar", S_OK, 0},
77 {"file://incomplete", "\\\\incomplete", S_OK, 0},
78
79 /* 3 leading (back)slashes (omitting hostname) */
80 {"file:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
81 {"File:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
82 {"file:///c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
83 {"file:///foo%20ba%2fr", "\\foo ba/r", S_OK, 0},
84 {"file:///foo/bar/", "\\foo\\bar\\", S_OK, 0},
85 {"file:///localhost/c:/foo/bar", "\\localhost\\c:\\foo\\bar", S_OK, 0},
86
87 /* 4 leading (back)slashes */
88 {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
89 {"file:////c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0},
90 {"file:////foo%20ba%2fr", "\\\\foo%20ba%2fr", S_OK, 0},
91
92 /* 5 and more leading (back)slashes */
93 {"file://///c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0},
94 {"file://///c:/foo%20ba%2fr", "\\\\c:\\foo ba/r", S_OK, 0},
95 {"file://///foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0},
96 {"file://////c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0},
97
98 /* Leading (back)slashes cannot be escaped */
99 {"file:%2f%2flocalhost%2fc:/foo/bar", "//localhost/c:\\foo\\bar", S_OK, 0},
100 {"file:%5C%5Clocalhost%5Cc:/foo/bar", "\\\\localhost\\c:\\foo\\bar", S_OK, 0},
101
102 /* Hostname handling */
103 {"file://l%6fcalhost/c:/foo/bar", "\\\\localhostc:\\foo\\bar", S_OK, 0},
104 {"file://localhost:80/c:/foo/bar", "\\\\localhost:80c:\\foo\\bar", S_OK, 0},
105 {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK, 0},
106 {"file://host//c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0},
107 {"file://host/\\c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0},
108 {"file://host/c:foo/bar", "\\\\hostc:foo\\bar", S_OK, 0},
109 {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK, 0},
110 {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK, 0},
111 {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK, 0},
112 {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK, 0},
113 {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK, 0},
114 {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK, 0},
115 {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK, 0},
116
117 /* Not file URLs */
118 {"c:\\foo\\bar", NULL, E_INVALIDARG, 0},
119 {"foo/bar", NULL, E_INVALIDARG, 0},
120 {"http://foo/bar", NULL, E_INVALIDARG, 0},
121
122 };
123
124
125 static struct {
126 const char *path;
127 BOOL expect;
128 } TEST_PATH_IS_URL[] = {
129 {"http://foo/bar", TRUE},
130 {"c:\\foo\\bar", FALSE},
131 {"c:/foo/bar", FALSE},
132 {"foo://foo/bar", TRUE},
133 {"foo\\bar", FALSE},
134 {"foo.bar", FALSE},
135 {"bogusscheme:", TRUE},
136 {"http:partial", TRUE},
137 {"www.winehq.org", FALSE},
138 /* More examples that the user might enter as the browser start page */
139 {"winehq.org", FALSE},
140 {"ftp.winehq.org", FALSE},
141 {"http://winehq.org", TRUE},
142 {"http://www.winehq.org", TRUE},
143 {"https://winehq.org", TRUE},
144 {"https://www.winehq.org", TRUE},
145 {"ftp://winehq.org", TRUE},
146 {"ftp://ftp.winehq.org", TRUE},
147 {"file://does_not_exist.txt", TRUE},
148 {"about:blank", TRUE},
149 {"about:home", TRUE},
150 {"about:mozilla", TRUE},
151 /* scheme is case independent */
152 {"HTTP://www.winehq.org", TRUE},
153 /* a space at the start is not allowed */
154 {" http://www.winehq.org", FALSE},
155 {"", FALSE},
156 {NULL, FALSE}
157 };
158
159 static const struct {
160 const char *path;
161 const char *result;
162 } TEST_PATH_UNQUOTE_SPACES[] = {
163 { "abcdef", "abcdef" },
164 { "\"abcdef\"", "abcdef" },
165 { "\"abcdef", "\"abcdef" },
166 { "abcdef\"", "abcdef\"" },
167 { "\"\"abcdef\"\"", "\"abcdef\"" },
168 { "abc\"def", "abc\"def" },
169 { "\"abc\"def", "\"abc\"def" },
170 { "\"abc\"def\"", "abc\"def" },
171 { "\'abcdef\'", "\'abcdef\'" },
172 { "\"\"", "" },
173 { "\"", "" }
174 };
175
176 /* ################ */
177
178 static LPWSTR GetWideString(const char *src)
179 {
180 WCHAR *ret;
181
182 if (!src)
183 return NULL;
184
185 ret = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
186
187 MultiByteToWideChar(CP_ACP, 0, src, -1, ret, INTERNET_MAX_URL_LENGTH);
188
189 return ret;
190 }
191
192 static void FreeWideString(LPWSTR wszString)
193 {
194 HeapFree(GetProcessHeap(), 0, wszString);
195 }
196
197 static LPSTR strdupA(LPCSTR p)
198 {
199 LPSTR ret;
200 DWORD len = (strlen(p) + 1);
201 ret = HeapAlloc(GetProcessHeap(), 0, len);
202 memcpy(ret, p, len);
203 return ret;
204 }
205
206 /* ################ */
207
208 static void test_PathSearchAndQualify(void)
209 {
210 WCHAR path1[] = {'c',':','\\','f','o','o',0};
211 WCHAR expect1[] = {'c',':','\\','f','o','o',0};
212 WCHAR path2[] = {'c',':','f','o','o',0};
213 WCHAR c_drive[] = {'c',':',0};
214 WCHAR foo[] = {'f','o','o',0};
215 WCHAR path3[] = {'\\','f','o','o',0};
216 WCHAR winini[] = {'w','i','n','.','i','n','i',0};
217 WCHAR out[MAX_PATH];
218 WCHAR cur_dir[MAX_PATH];
219 WCHAR dot[] = {'.',0};
220
221 /* c:\foo */
222 ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
223 "PathSearchAndQualify rets 0\n");
224 ok(!lstrcmpiW(out, expect1), "strings don't match\n");
225
226 /* c:foo */
227 ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
228 "PathSearchAndQualify rets 0\n");
229 GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
230 PathAddBackslashW(cur_dir);
231 lstrcatW(cur_dir, foo);
232 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
233
234 /* foo */
235 ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
236 "PathSearchAndQualify rets 0\n");
237 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
238 PathAddBackslashW(cur_dir);
239 lstrcatW(cur_dir, foo);
240 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
241
242 /* \foo */
243 ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
244 "PathSearchAndQualify rets 0\n");
245 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
246 lstrcpyW(cur_dir + 2, path3);
247 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
248
249 /* win.ini */
250 ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
251 "PathSearchAndQualify rets 0\n");
252 if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
253 GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
254 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
255
256 }
257
258 static void test_PathCreateFromUrl(void)
259 {
260 size_t i;
261 char ret_path[INTERNET_MAX_URL_LENGTH];
262 DWORD len, len2, ret;
263 WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
264 WCHAR *pathW, *urlW;
265
266 if (!pPathCreateFromUrlA) {
267 win_skip("PathCreateFromUrlA not found\n");
268 return;
269 }
270
271 /* Won't say how much is needed without a buffer */
272 len = 0xdeca;
273 ret = pPathCreateFromUrlA("file://foo", NULL, &len, 0);
274 ok(ret == E_INVALIDARG, "got 0x%08x expected E_INVALIDARG\n", ret);
275 ok(len == 0xdeca, "got %x expected 0xdeca\n", len);
276
277 /* Test the decoding itself */
278 for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
279 len = INTERNET_MAX_URL_LENGTH;
280 ret = pPathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
281 todo_wine_if (TEST_PATHFROMURL[i].todo & 0x1)
282 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url);
283 if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) {
284 if(!(TEST_PATHFROMURL[i].todo & 0x2)) {
285 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);
286 ok(len == strlen(ret_path), "ret len %d from url %s\n", len, TEST_PATHFROMURL[i].url);
287 } else todo_wine
288 /* Wrong string, don't bother checking the length */
289 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);
290 }
291
292 if (pPathCreateFromUrlW) {
293 len = INTERNET_MAX_URL_LENGTH;
294 pathW = GetWideString(TEST_PATHFROMURL[i].path);
295 urlW = GetWideString(TEST_PATHFROMURL[i].url);
296 ret = pPathCreateFromUrlW(urlW, ret_pathW, &len, 0);
297 WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),NULL,NULL);
298 todo_wine_if (TEST_PATHFROMURL[i].todo & 0x1)
299 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
300 if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) {
301 if(!(TEST_PATHFROMURL[i].todo & 0x2)) {
302 ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n",
303 ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
304 ok(len == lstrlenW(ret_pathW), "ret len %d from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
305 } else todo_wine
306 /* Wrong string, don't bother checking the length */
307 ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n",
308 ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
309 }
310
311 if (SUCCEEDED(ret))
312 {
313 /* Check what happens if the buffer is too small */
314 len2 = 2;
315 ret = pPathCreateFromUrlW(urlW, ret_pathW, &len2, 0);
316 ok(ret == E_POINTER, "ret %08x, expected E_POINTER from url %s\n", ret, TEST_PATHFROMURL[i].url);
317 todo_wine_if (TEST_PATHFROMURL[i].todo & 0x4)
318 ok(len2 == len + 1, "got len = %d expected %d from url %s\n", len2, len + 1, TEST_PATHFROMURL[i].url);
319 }
320
321 FreeWideString(urlW);
322 FreeWideString(pathW);
323 }
324 }
325
326 if (pPathCreateFromUrlAlloc)
327 {
328 static const WCHAR fileW[] = {'f','i','l','e',':','/','/','f','o','o',0};
329 static const WCHAR fooW[] = {'\\','\\','f','o','o',0};
330
331 pathW = NULL;
332 ret = pPathCreateFromUrlAlloc(fileW, &pathW, 0);
333 ok(ret == S_OK, "got 0x%08x expected S_OK\n", ret);
334 ok(lstrcmpiW(pathW, fooW) == 0, "got %s expected %s\n", wine_dbgstr_w(pathW), wine_dbgstr_w(fooW));
335 HeapFree(GetProcessHeap(), 0, pathW);
336 }
337 }
338
339
340 static void test_PathIsUrl(void)
341 {
342 size_t i;
343 BOOL ret;
344
345 for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
346 ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
347 ok(ret == TEST_PATH_IS_URL[i].expect,
348 "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
349 TEST_PATH_IS_URL[i].expect);
350 }
351 }
352
353 static const DWORD SHELL_charclass[] =
354 {
355 0x00000000, 0x00000000, 0x00000000, 0x00000000,
356 0x00000000, 0x00000000, 0x00000000, 0x00000000,
357 0x00000000, 0x00000000, 0x00000000, 0x00000000,
358 0x00000000, 0x00000000, 0x00000000, 0x00000000,
359 0x00000000, 0x00000000, 0x00000000, 0x00000000,
360 0x00000000, 0x00000000, 0x00000000, 0x00000000,
361 0x00000000, 0x00000000, 0x00000000, 0x00000000,
362 0x00000000, 0x00000000, 0x00000000, 0x00000000,
363 0x00000080, 0x00000100, 0x00000200, 0x00000100,
364 0x00000100, 0x00000100, 0x00000100, 0x00000100,
365 0x00000100, 0x00000100, 0x00000002, 0x00000100,
366 0x00000040, 0x00000100, 0x00000004, 0x00000000,
367 0x00000100, 0x00000100, 0x00000100, 0x00000100,
368 0x00000100, 0x00000100, 0x00000100, 0x00000100,
369 0x00000100, 0x00000100, 0x00000010, 0x00000020,
370 0x00000000, 0x00000100, 0x00000000, 0x00000001,
371 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
372 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
373 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
374 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
375 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
376 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
377 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
378 0x00000008, 0x00000100, 0x00000100, 0x00000100,
379 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
380 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
381 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
382 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
383 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
384 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
385 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
386 0x00000000, 0x00000100, 0x00000100
387 };
388
389 static void test_PathIsValidCharA(void)
390 {
391 BOOL ret;
392 unsigned int c;
393
394 /* For whatever reason, PathIsValidCharA and PathAppendA share the same
395 * ordinal number in some native versions. Check this to prevent a crash.
396 */
397 if (!pPathIsValidCharA || pPathIsValidCharA == (void*)pPathAppendA)
398 {
399 win_skip("PathIsValidCharA isn't available\n");
400 return;
401 }
402
403 for (c = 0; c < 0x7f; c++)
404 {
405 ret = pPathIsValidCharA( c, ~0U );
406 ok ( ret || !SHELL_charclass[c], "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
407 }
408
409 for (c = 0x7f; c <= 0xff; c++)
410 {
411 ret = pPathIsValidCharA( c, ~0U );
412 ok ( ret, "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
413 }
414 }
415
416 static void test_PathIsValidCharW(void)
417 {
418 BOOL ret;
419 unsigned int c;
420
421 if (!pPathIsValidCharW)
422 {
423 win_skip("PathIsValidCharW isn't available\n");
424 return;
425 }
426
427 for (c = 0; c < 0x7f; c++)
428 {
429 ret = pPathIsValidCharW( c, ~0U );
430 ok ( ret || !SHELL_charclass[c], "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
431 }
432
433 for (c = 0x007f; c <= 0xffff; c++)
434 {
435 ret = pPathIsValidCharW( c, ~0U );
436 ok ( ret, "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
437 }
438 }
439
440 static void test_PathMakePretty(void)
441 {
442 char buff[MAX_PATH];
443
444 ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
445 buff[0] = '\0';
446 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
447
448 strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
449 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
450 ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
451 "PathMakePretty: Long UC name not changed\n");
452
453 strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
454 ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
455 ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
456 "PathMakePretty: Failed but modified path\n");
457
458 strcpy(buff, "TEST");
459 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Short name failed\n");
460 ok (strcmp(buff, "Test") == 0, "PathMakePretty: 1st char lowercased %s\n", buff);
461 }
462
463 static void test_PathMatchSpec(void)
464 {
465 static const char file[] = "c:\\foo\\bar\\filename.ext";
466 static const char spec1[] = ".ext";
467 static const char spec2[] = "*.ext";
468 static const char spec3[] = "*.ext ";
469 static const char spec4[] = " *.ext";
470 static const char spec5[] = "* .ext";
471 static const char spec6[] = "*. ext";
472 static const char spec7[] = "* . ext";
473 static const char spec8[] = "*.e?t";
474 static const char spec9[] = "filename.ext";
475 static const char spec10[] = "*bar\\filename.ext";
476 static const char spec11[] = " foo; *.ext";
477 static const char spec12[] = "*.ext;*.bar";
478 static const char spec13[] = "*bar*";
479
480 ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
481 ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
482 ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
483 ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
484 todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
485 todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
486 ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
487 ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
488 ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
489 ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
490 ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
491 ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
492 ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
493 }
494
495 static void test_PathCombineW(void)
496 {
497 LPWSTR wszString, wszString2;
498 WCHAR wbuf[MAX_PATH+1], wstr1[MAX_PATH] = {'C',':','\\',0}, wstr2[MAX_PATH];
499 static const WCHAR expout[] = {'C',':','\\','A','A',0};
500 int i;
501
502 if (!pPathCombineW)
503 {
504 win_skip("PathCombineW isn't available\n");
505 return;
506 }
507
508 wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
509
510 /* NULL test */
511 wszString = pPathCombineW(NULL, NULL, NULL);
512 ok (wszString == NULL, "Expected a NULL return\n");
513
514 /* Some NULL */
515 wszString2[0] = 'a';
516 wszString = pPathCombineW(wszString2, NULL, NULL);
517 ok (wszString == NULL ||
518 broken(wszString[0] == 'a'), /* Win95 and some W2K */
519 "Expected a NULL return\n");
520 ok (wszString2[0] == 0 ||
521 broken(wszString2[0] == 'a'), /* Win95 and some W2K */
522 "Destination string not empty\n");
523
524 HeapFree(GetProcessHeap(), 0, wszString2);
525
526 /* overflow test */
527 wstr2[0] = wstr2[1] = wstr2[2] = 'A';
528 for (i=3; i<MAX_PATH/2; i++)
529 wstr1[i] = wstr2[i] = 'A';
530 wstr1[(MAX_PATH/2) - 1] = wstr2[MAX_PATH/2] = 0;
531 memset(wbuf, 0xbf, sizeof(wbuf));
532
533 wszString = pPathCombineW(wbuf, wstr1, wstr2);
534 ok(wszString == NULL, "Expected a NULL return\n");
535 ok(wbuf[0] == 0 ||
536 broken(wbuf[0] == 0xbfbf), /* Win95 and some W2K */
537 "Buffer contains data\n");
538
539 /* PathCombineW can be used in place */
540 wstr1[3] = 0;
541 wstr2[2] = 0;
542 ok(PathCombineW(wstr1, wstr1, wstr2) == wstr1, "Expected a wstr1 return\n");
543 ok(StrCmpW(wstr1, expout) == 0, "Unexpected PathCombine output\n");
544 }
545
546
547 #define LONG_LEN (MAX_PATH * 2)
548 #define HALF_LEN (MAX_PATH / 2 + 1)
549
550 static void test_PathCombineA(void)
551 {
552 LPSTR str;
553 char dest[MAX_PATH];
554 char too_long[LONG_LEN];
555 char one[HALF_LEN], two[HALF_LEN];
556
557 /* try NULL dest */
558 SetLastError(0xdeadbeef);
559 str = PathCombineA(NULL, "C:\\", "one\\two\\three");
560 ok(str == NULL, "Expected NULL, got %p\n", str);
561 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
562
563 /* try NULL dest and NULL directory */
564 SetLastError(0xdeadbeef);
565 str = PathCombineA(NULL, NULL, "one\\two\\three");
566 ok(str == NULL, "Expected NULL, got %p\n", str);
567 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
568
569 /* try all NULL*/
570 SetLastError(0xdeadbeef);
571 str = PathCombineA(NULL, NULL, NULL);
572 ok(str == NULL, "Expected NULL, got %p\n", str);
573 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
574
575 /* try NULL file part */
576 SetLastError(0xdeadbeef);
577 lstrcpyA(dest, "control");
578 str = PathCombineA(dest, "C:\\", NULL);
579 ok(str == dest, "Expected str == dest, got %p\n", str);
580 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
581 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
582
583 /* try empty file part */
584 SetLastError(0xdeadbeef);
585 lstrcpyA(dest, "control");
586 str = PathCombineA(dest, "C:\\", "");
587 ok(str == dest, "Expected str == dest, got %p\n", str);
588 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
589 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
590
591 /* try empty directory and file part */
592 SetLastError(0xdeadbeef);
593 lstrcpyA(dest, "control");
594 str = PathCombineA(dest, "", "");
595 ok(str == dest, "Expected str == dest, got %p\n", str);
596 ok(!lstrcmpA(str, "\\") ||
597 broken(!lstrcmpA(str, "control")), /* Win95 and some W2K */
598 "Expected \\, got %s\n", str);
599 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
600
601 /* try NULL directory */
602 SetLastError(0xdeadbeef);
603 lstrcpyA(dest, "control");
604 str = PathCombineA(dest, NULL, "one\\two\\three");
605 ok(str == dest, "Expected str == dest, got %p\n", str);
606 ok(!lstrcmpA(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
607 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
608
609 /* try NULL directory and empty file part */
610 SetLastError(0xdeadbeef);
611 lstrcpyA(dest, "control");
612 str = PathCombineA(dest, NULL, "");
613 ok(str == dest, "Expected str == dest, got %p\n", str);
614 ok(!lstrcmpA(str, "\\") ||
615 broken(!lstrcmpA(str, "one\\two\\three")), /* Win95 and some W2K */
616 "Expected \\, got %s\n", str);
617 ok(GetLastError() == 0xdeadbeef ||
618 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win95 */
619 "Expected 0xdeadbeef, got %d\n", GetLastError());
620
621 /* try NULL directory and file part */
622 SetLastError(0xdeadbeef);
623 lstrcpyA(dest, "control");
624 str = PathCombineA(dest, NULL, NULL);
625 ok(str == NULL ||
626 broken(str != NULL), /* Win95 and some W2K */
627 "Expected str == NULL, got %p\n", str);
628 ok(!dest[0] || broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
629 "Expected 0 length, got %i\n", lstrlenA(dest));
630 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
631
632 /* try directory without backslash */
633 SetLastError(0xdeadbeef);
634 lstrcpyA(dest, "control");
635 str = PathCombineA(dest, "C:", "one\\two\\three");
636 ok(str == dest, "Expected str == dest, got %p\n", str);
637 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
638 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
639
640 /* try directory with backslash */
641 SetLastError(0xdeadbeef);
642 lstrcpyA(dest, "control");
643 str = PathCombineA(dest, "C:\\", "one\\two\\three");
644 ok(str == dest, "Expected str == dest, got %p\n", str);
645 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
646 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
647
648 /* try directory with backslash and file with prepended backslash */
649 SetLastError(0xdeadbeef);
650 lstrcpyA(dest, "control");
651 str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
652 ok(str == dest, "Expected str == dest, got %p\n", str);
653 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
654 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
655
656 /* try previous test, with backslash appended as well */
657 SetLastError(0xdeadbeef);
658 lstrcpyA(dest, "control");
659 str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
660 ok(str == dest, "Expected str == dest, got %p\n", str);
661 ok(!lstrcmpA(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
662 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
663
664 /* try a relative directory */
665 SetLastError(0xdeadbeef);
666 lstrcpyA(dest, "control");
667 str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
668 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
669 /* Vista fails which probably makes sense as PathCombineA expects an absolute dir */
670 if (str)
671 {
672 ok(str == dest, "Expected str == dest, got %p\n", str);
673 ok(!lstrcmpA(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
674 }
675
676 /* try forward slashes */
677 SetLastError(0xdeadbeef);
678 lstrcpyA(dest, "control");
679 str = PathCombineA(dest, "C:\\", "one/two/three\\");
680 ok(str == dest, "Expected str == dest, got %p\n", str);
681 ok(!lstrcmpA(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
682 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
683
684 /* try a really weird directory */
685 SetLastError(0xdeadbeef);
686 lstrcpyA(dest, "control");
687 str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
688 ok(str == dest, "Expected str == dest, got %p\n", str);
689 ok(!lstrcmpA(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
690 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
691
692 /* try periods */
693 SetLastError(0xdeadbeef);
694 lstrcpyA(dest, "control");
695 str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
696 ok(str == dest, "Expected str == dest, got %p\n", str);
697 ok(!lstrcmpA(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
698 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
699
700 /* try .. as file */
701 /* try forward slashes */
702 SetLastError(0xdeadbeef);
703 lstrcpyA(dest, "control");
704 str = PathCombineA(dest, "C:\\", "..");
705 ok(str == dest, "Expected str == dest, got %p\n", str);
706 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
707 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
708
709 memset(too_long, 'a', LONG_LEN);
710 too_long[LONG_LEN - 1] = '\0';
711
712 /* try a file longer than MAX_PATH */
713 SetLastError(0xdeadbeef);
714 lstrcpyA(dest, "control");
715 str = PathCombineA(dest, "C:\\", too_long);
716 ok(str == NULL, "Expected str == NULL, got %p\n", str);
717 ok(!dest[0] || broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
718 "Expected 0 length, got %i\n", lstrlenA(dest));
719 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
720
721 /* try a directory longer than MAX_PATH */
722 SetLastError(0xdeadbeef);
723 lstrcpyA(dest, "control");
724 str = PathCombineA(dest, too_long, "one\\two\\three");
725 ok(str == NULL, "Expected str == NULL, got %p\n", str);
726 ok(!dest[0] || broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
727 "Expected 0 length, got %i\n", lstrlenA(dest));
728 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
729
730 memset(one, 'b', HALF_LEN);
731 memset(two, 'c', HALF_LEN);
732 one[HALF_LEN - 1] = '\0';
733 two[HALF_LEN - 1] = '\0';
734
735 /* destination string is longer than MAX_PATH, but not the constituent parts */
736 SetLastError(0xdeadbeef);
737 lstrcpyA(dest, "control");
738 str = PathCombineA(dest, one, two);
739 ok(str == NULL, "Expected str == NULL, got %p\n", str);
740 ok(!dest[0] || broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
741 "Expected 0 length, got %i\n", lstrlenA(dest));
742 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
743 }
744
745 static void test_PathAddBackslash(void)
746 {
747 LPSTR str;
748 char path[MAX_PATH];
749 char too_long[LONG_LEN];
750
751 /* try a NULL path */
752 SetLastError(0xdeadbeef);
753 str = PathAddBackslashA(NULL);
754 ok(str == NULL, "Expected str == NULL, got %p\n", str);
755 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
756
757 /* try an empty path */
758 path[0] = '\0';
759 SetLastError(0xdeadbeef);
760 str = PathAddBackslashA(path);
761 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
762 ok(!path[0], "Expected empty string, got %i\n", lstrlenA(path));
763 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
764
765 /* try a relative path */
766 lstrcpyA(path, "one\\two");
767 SetLastError(0xdeadbeef);
768 str = PathAddBackslashA(path);
769 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
770 ok(!lstrcmpA(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
771 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
772
773 /* try periods */
774 lstrcpyA(path, "one\\..\\two");
775 SetLastError(0xdeadbeef);
776 str = PathAddBackslashA(path);
777 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
778 ok(!lstrcmpA(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
779 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
780
781 /* try just a space */
782 lstrcpyA(path, " ");
783 SetLastError(0xdeadbeef);
784 str = PathAddBackslashA(path);
785 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
786 ok(!lstrcmpA(path, " \\"), "Expected \\, got %s\n", path);
787 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
788
789 /* path already has backslash */
790 lstrcpyA(path, "C:\\one\\");
791 SetLastError(0xdeadbeef);
792 str = PathAddBackslashA(path);
793 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
794 ok(!lstrcmpA(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
795 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
796
797 memset(too_long, 'a', LONG_LEN);
798 too_long[LONG_LEN - 1] = '\0';
799
800 /* path is longer than MAX_PATH */
801 SetLastError(0xdeadbeef);
802 str = PathAddBackslashA(too_long);
803 ok(str == NULL, "Expected str == NULL, got %p\n", str);
804 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
805 }
806
807 static void test_PathAppendA(void)
808 {
809 char path[MAX_PATH];
810 char too_long[LONG_LEN];
811 char half[HALF_LEN];
812 BOOL res;
813
814 lstrcpyA(path, "C:\\one");
815
816 /* try NULL pszMore */
817 SetLastError(0xdeadbeef);
818 res = PathAppendA(path, NULL);
819 ok(!res, "Expected failure\n");
820 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
821 ok(!lstrcmpA(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
822
823 /* try empty pszMore */
824 SetLastError(0xdeadbeef);
825 res = PathAppendA(path, "");
826 ok(res, "Expected success\n");
827 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
828 ok(!lstrcmpA(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
829
830 /* try NULL pszPath */
831 SetLastError(0xdeadbeef);
832 res = PathAppendA(NULL, "two\\three");
833 ok(!res, "Expected failure\n");
834 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
835
836 /* try empty pszPath */
837 path[0] = '\0';
838 SetLastError(0xdeadbeef);
839 res = PathAppendA(path, "two\\three");
840 ok(res, "Expected success\n");
841 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
842 ok(!lstrcmpA(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
843
844 /* try empty pszPath and empty pszMore */
845 path[0] = '\0';
846 SetLastError(0xdeadbeef);
847 res = PathAppendA(path, "");
848 ok(res, "Expected success\n");
849 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
850 ok(!lstrcmpA(path, "\\"), "Expected \\, got %s\n", path);
851
852 /* try legit params */
853 lstrcpyA(path, "C:\\one");
854 SetLastError(0xdeadbeef);
855 res = PathAppendA(path, "two\\three");
856 ok(res, "Expected success\n");
857 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
858 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
859
860 /* try pszPath with backslash after it */
861 lstrcpyA(path, "C:\\one\\");
862 SetLastError(0xdeadbeef);
863 res = PathAppendA(path, "two\\three");
864 ok(res, "Expected success\n");
865 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
866 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
867
868 /* try pszMore with backslash before it */
869 lstrcpyA(path, "C:\\one");
870 SetLastError(0xdeadbeef);
871 res = PathAppendA(path, "\\two\\three");
872 ok(res, "Expected success\n");
873 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
874 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
875
876 /* try pszMore with backslash after it */
877 lstrcpyA(path, "C:\\one");
878 SetLastError(0xdeadbeef);
879 res = PathAppendA(path, "two\\three\\");
880 ok(res, "Expected success\n");
881 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
882 ok(!lstrcmpA(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
883
884 /* try spaces in pszPath */
885 lstrcpyA(path, "C: \\ one ");
886 SetLastError(0xdeadbeef);
887 res = PathAppendA(path, "two\\three");
888 ok(res, "Expected success\n");
889 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
890 ok(!lstrcmpA(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
891
892 /* try spaces in pszMore */
893 lstrcpyA(path, "C:\\one");
894 SetLastError(0xdeadbeef);
895 res = PathAppendA(path, " two \\ three ");
896 ok(res, "Expected success\n");
897 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
898 ok(!lstrcmpA(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
899
900 /* pszPath is too long */
901 memset(too_long, 'a', LONG_LEN);
902 too_long[LONG_LEN - 1] = '\0';
903 SetLastError(0xdeadbeef);
904 res = PathAppendA(too_long, "two\\three");
905 ok(!res, "Expected failure\n");
906 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
907 ok(!too_long[0] || broken(lstrlenA(too_long) == (LONG_LEN - 1)), /* Win95 and some W2K */
908 "Expected length of too_long to be zero, got %i\n", lstrlenA(too_long));
909
910 /* pszMore is too long */
911 lstrcpyA(path, "C:\\one");
912 memset(too_long, 'a', LONG_LEN);
913 too_long[LONG_LEN - 1] = '\0';
914 SetLastError(0xdeadbeef);
915 res = PathAppendA(path, too_long);
916 ok(!res, "Expected failure\n");
917 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
918 ok(!path[0] || broken(!lstrcmpA(path, "C:\\one")), /* Win95 and some W2K */
919 "Expected length of path to be zero, got %i\n", lstrlenA(path));
920
921 /* both params combined are too long */
922 memset(path, 'a', HALF_LEN);
923 path[HALF_LEN - 1] = '\0';
924 memset(half, 'b', HALF_LEN);
925 half[HALF_LEN - 1] = '\0';
926 SetLastError(0xdeadbeef);
927 res = PathAppendA(path, half);
928 ok(!res, "Expected failure\n");
929 ok(!path[0] || broken(lstrlenA(path) == (HALF_LEN - 1)), /* Win95 and some W2K */
930 "Expected length of path to be zero, got %i\n", lstrlenA(path));
931 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
932 }
933
934 static void test_PathCanonicalizeA(void)
935 {
936 char dest[LONG_LEN + MAX_PATH];
937 char too_long[LONG_LEN];
938 BOOL res;
939
940 /* try a NULL source */
941 lstrcpyA(dest, "test");
942 SetLastError(0xdeadbeef);
943 res = PathCanonicalizeA(dest, NULL);
944 ok(!res, "Expected failure\n");
945 ok(GetLastError() == ERROR_INVALID_PARAMETER,
946 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
947 ok(dest[0] == 0 || !lstrcmpA(dest, "test"),
948 "Expected either an empty string (Vista) or test, got %s\n", dest);
949
950 /* try an empty source */
951 lstrcpyA(dest, "test");
952 SetLastError(0xdeadbeef);
953 res = PathCanonicalizeA(dest, "");
954 ok(res, "Expected success\n");
955 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
956 ok(!lstrcmpA(dest, "\\") ||
957 broken(!lstrcmpA(dest, "test")), /* Win95 and some W2K */
958 "Expected \\, got %s\n", dest);
959
960 /* try a NULL dest */
961 SetLastError(0xdeadbeef);
962 res = PathCanonicalizeA(NULL, "C:\\");
963 ok(!res, "Expected failure\n");
964 ok(GetLastError() == ERROR_INVALID_PARAMETER,
965 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
966
967 /* try empty dest */
968 dest[0] = '\0';
969 SetLastError(0xdeadbeef);
970 res = PathCanonicalizeA(dest, "C:\\");
971 ok(res, "Expected success\n");
972 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
973 ok(!lstrcmpA(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
974
975 /* try non-empty dest */
976 lstrcpyA(dest, "test");
977 SetLastError(0xdeadbeef);
978 res = PathCanonicalizeA(dest, "C:\\");
979 ok(res, "Expected success\n");
980 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
981 ok(!lstrcmpA(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
982
983 /* try a space for source */
984 lstrcpyA(dest, "test");
985 SetLastError(0xdeadbeef);
986 res = PathCanonicalizeA(dest, " ");
987 ok(res, "Expected success\n");
988 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
989 ok(!lstrcmpA(dest, " "), "Expected ' ', got %s\n", dest);
990
991 /* try a relative path */
992 lstrcpyA(dest, "test");
993 SetLastError(0xdeadbeef);
994 res = PathCanonicalizeA(dest, "one\\two");
995 ok(res, "Expected success\n");
996 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
997 ok(!lstrcmpA(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
998
999 /* try current dir and previous dir */
1000 lstrcpyA(dest, "test");
1001 SetLastError(0xdeadbeef);
1002 res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
1003 ok(res, "Expected success\n");
1004 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1005 ok(!lstrcmpA(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
1006
1007 /* try simple forward slashes */
1008 lstrcpyA(dest, "test");
1009 SetLastError(0xdeadbeef);
1010 res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
1011 ok(res, "Expected success\n");
1012 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1013 ok(!lstrcmpA(dest, "C:\\one/two/three\\four/five\\six"),
1014 "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
1015
1016 /* try simple forward slashes with same dir */
1017 lstrcpyA(dest, "test");
1018 SetLastError(0xdeadbeef);
1019 res = PathCanonicalizeA(dest, "C:\\one/.\\two");
1020 ok(res, "Expected success\n");
1021 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1022 ok(!lstrcmpA(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
1023
1024 /* try simple forward slashes with change dir */
1025 lstrcpyA(dest, "test");
1026 SetLastError(0xdeadbeef);
1027 res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
1028 ok(res, "Expected success\n");
1029 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1030 ok(!lstrcmpA(dest, "C:\\one/.") ||
1031 !lstrcmpA(dest, "C:\\one/"), /* Vista */
1032 "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest);
1033
1034 /* try forward slashes with change dirs
1035 * NOTE: if there is a forward slash in between two backslashes,
1036 * everything in between the two backslashes is considered on dir
1037 */
1038 lstrcpyA(dest, "test");
1039 SetLastError(0xdeadbeef);
1040 res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
1041 ok(res, "Expected success\n");
1042 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1043 ok(!lstrcmpA(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
1044
1045 /* try src is too long */
1046 memset(too_long, 'a', LONG_LEN);
1047 too_long[LONG_LEN - 1] = '\0';
1048 lstrcpyA(dest, "test");
1049 SetLastError(0xdeadbeef);
1050 res = PathCanonicalizeA(dest, too_long);
1051 ok(!res ||
1052 broken(res), /* Win95, some W2K and XP-SP1 */
1053 "Expected failure\n");
1054 todo_wine
1055 {
1056 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */,
1057 "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
1058 }
1059 ok(lstrlenA(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlenA(too_long));
1060 }
1061
1062 static void test_PathFindExtensionA(void)
1063 {
1064 LPSTR ext;
1065 char path[MAX_PATH];
1066 char too_long[LONG_LEN];
1067
1068 /* try a NULL path */
1069 SetLastError(0xdeadbeef);
1070 ext = PathFindExtensionA(NULL);
1071 ok(ext == NULL, "Expected NULL, got %p\n", ext);
1072 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1073
1074 /* try an empty path */
1075 path[0] = '\0';
1076 SetLastError(0xdeadbeef);
1077 ext = PathFindExtensionA(path);
1078 ok(ext == path, "Expected ext == path, got %p\n", ext);
1079 ok(!ext[0], "Expected length 0, got %i\n", lstrlenA(ext));
1080 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1081
1082 /* try a path without an extension */
1083 lstrcpyA(path, "file");
1084 SetLastError(0xdeadbeef);
1085 ext = PathFindExtensionA(path);
1086 ok(ext == path + lstrlenA(path), "Expected ext == path, got %p\n", ext);
1087 ok(!ext[0], "Expected length 0, got %i\n", lstrlenA(ext));
1088 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1089
1090 /* try a path with an extension */
1091 lstrcpyA(path, "file.txt");
1092 SetLastError(0xdeadbeef);
1093 ext = PathFindExtensionA(path);
1094 ok(ext == path + lstrlenA("file"),
1095 "Expected ext == path + lstrlenA(\"file\"), got %p\n", ext);
1096 ok(!lstrcmpA(ext, ".txt"), "Expected .txt, got %s\n", ext);
1097 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1098
1099 /* try a path with two extensions */
1100 lstrcpyA(path, "file.txt.doc");
1101 SetLastError(0xdeadbeef);
1102 ext = PathFindExtensionA(path);
1103 ok(ext == path + lstrlenA("file.txt"),
1104 "Expected ext == path + lstrlenA(\"file.txt\"), got %p\n", ext);
1105 ok(!lstrcmpA(ext, ".doc"), "Expected .txt, got %s\n", ext);
1106 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1107
1108 /* try a path longer than MAX_PATH without an extension*/
1109 memset(too_long, 'a', LONG_LEN);
1110 too_long[LONG_LEN - 1] = '\0';
1111 SetLastError(0xdeadbeef);
1112 ext = PathFindExtensionA(too_long);
1113 ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
1114 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1115
1116 /* try a path longer than MAX_PATH with an extension*/
1117 memset(too_long, 'a', LONG_LEN);
1118 too_long[LONG_LEN - 1] = '\0';
1119 lstrcpyA(too_long + 300, ".abcde");
1120 too_long[lstrlenA(too_long)] = 'a';
1121 SetLastError(0xdeadbeef);
1122 ext = PathFindExtensionA(too_long);
1123 ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1124 ok(lstrlenA(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlenA(ext));
1125 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1126 }
1127
1128 static void test_PathBuildRootA(void)
1129 {
1130 LPSTR root;
1131 char path[10];
1132 char root_expected[26][4];
1133 char drive;
1134 int j;
1135
1136 /* set up the expected paths */
1137 for (drive = 'A'; drive <= 'Z'; drive++)
1138 sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1139
1140 /* test the expected values */
1141 for (j = 0; j < 26; j++)
1142 {
1143 SetLastError(0xdeadbeef);
1144 lstrcpyA(path, "aaaaaaaaa");
1145 root = PathBuildRootA(path, j);
1146 ok(root == path, "Expected root == path, got %p\n", root);
1147 ok(!lstrcmpA(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1148 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1149 }
1150
1151 /* test a negative drive number */
1152 SetLastError(0xdeadbeef);
1153 lstrcpyA(path, "aaaaaaaaa");
1154 root = PathBuildRootA(path, -1);
1155 ok(root == path, "Expected root == path, got %p\n", root);
1156 ok(!lstrcmpA(path, "aaaaaaaaa") || !path[0], /* Vista */
1157 "Expected aaaaaaaaa or empty string, got %s\n", path);
1158 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1159
1160 /* test a drive number greater than 25 */
1161 SetLastError(0xdeadbeef);
1162 lstrcpyA(path, "aaaaaaaaa");
1163 root = PathBuildRootA(path, 26);
1164 ok(root == path, "Expected root == path, got %p\n", root);
1165 ok(!lstrcmpA(path, "aaaaaaaaa") || !path[0], /* Vista */
1166 "Expected aaaaaaaaa or empty string, got %s\n", path);
1167 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1168
1169 /* length of path is less than 4 */
1170 SetLastError(0xdeadbeef);
1171 lstrcpyA(path, "aa");
1172 root = PathBuildRootA(path, 0);
1173 ok(root == path, "Expected root == path, got %p\n", root);
1174 ok(!lstrcmpA(path, "A:\\"), "Expected A:\\, got %s\n", path);
1175 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1176
1177 /* path is NULL */
1178 SetLastError(0xdeadbeef);
1179 root = PathBuildRootA(NULL, 0);
1180 ok(root == NULL, "Expected root == NULL, got %p\n", root);
1181 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1182 }
1183
1184 static void test_PathCommonPrefixA(void)
1185 {
1186 char path1[MAX_PATH], path2[MAX_PATH];
1187 char out[MAX_PATH];
1188 int count;
1189
1190 /* test NULL path1 */
1191 SetLastError(0xdeadbeef);
1192 lstrcpyA(path2, "C:\\");
1193 lstrcpyA(out, "aaa");
1194 count = PathCommonPrefixA(NULL, path2, out);
1195 ok(count == 0, "Expected 0, got %i\n", count);
1196 todo_wine
1197 {
1198 ok(!lstrcmpA(out, "aaa"), "Expected aaa, got %s\n", out);
1199 }
1200 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1201 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1202
1203 /* test NULL path2 */
1204 SetLastError(0xdeadbeef);
1205 lstrcpyA(path1, "C:\\");
1206 lstrcpyA(out, "aaa");
1207 count = PathCommonPrefixA(path1, NULL, out);
1208 ok(count == 0, "Expected 0, got %i\n", count);
1209 todo_wine
1210 {
1211 ok(!lstrcmpA(out, "aaa"), "Expected aaa, got %s\n", out);
1212 }
1213 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1214 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1215
1216 /* test empty path1 */
1217 SetLastError(0xdeadbeef);
1218 path1[0] = '\0';
1219 lstrcpyA(path2, "C:\\");
1220 lstrcpyA(out, "aaa");
1221 count = PathCommonPrefixA(path1, path2, out);
1222 ok(count == 0, "Expected 0, got %i\n", count);
1223 ok(!out[0], "Expected 0 length out, got %i\n", lstrlenA(out));
1224 ok(!path1[0], "Expected 0 length path1, got %i\n", lstrlenA(path1));
1225 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1226 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1227
1228 /* test empty path1 */
1229 SetLastError(0xdeadbeef);
1230 path2[0] = '\0';
1231 lstrcpyA(path1, "C:\\");
1232 lstrcpyA(out, "aaa");
1233 count = PathCommonPrefixA(path1, path2, out);
1234 ok(count == 0, "Expected 0, got %i\n", count);
1235 ok(!out[0], "Expected 0 length out, got %i\n", lstrlenA(out));
1236 ok(!path2[0], "Expected 0 length path2, got %i\n", lstrlenA(path2));
1237 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1238 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1239
1240 /* paths are legit, out is NULL */
1241 SetLastError(0xdeadbeef);
1242 lstrcpyA(path1, "C:\\");
1243 lstrcpyA(path2, "C:\\");
1244 count = PathCommonPrefixA(path1, path2, NULL);
1245 ok(count == 3, "Expected 3, got %i\n", count);
1246 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1247 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1248 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1249
1250 /* all parameters legit */
1251 SetLastError(0xdeadbeef);
1252 lstrcpyA(path1, "C:\\");
1253 lstrcpyA(path2, "C:\\");
1254 lstrcpyA(out, "aaa");
1255 count = PathCommonPrefixA(path1, path2, out);
1256 ok(count == 3, "Expected 3, got %i\n", count);
1257 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1258 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1259 ok(!lstrcmpA(out, "C:\\"), "Expected C:\\, got %s\n", out);
1260 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1261
1262 /* path1 and path2 not the same, but common prefix */
1263 SetLastError(0xdeadbeef);
1264 lstrcpyA(path1, "C:\\one\\two");
1265 lstrcpyA(path2, "C:\\one\\three");
1266 lstrcpyA(out, "aaa");
1267 count = PathCommonPrefixA(path1, path2, out);
1268 ok(count == 6, "Expected 6, got %i\n", count);
1269 ok(!lstrcmpA(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1270 ok(!lstrcmpA(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1271 ok(!lstrcmpA(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1272 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1273
1274 /* try . prefix */
1275 SetLastError(0xdeadbeef);
1276 lstrcpyA(path1, "one\\.two");
1277 lstrcpyA(path2, "one\\.three");
1278 lstrcpyA(out, "aaa");
1279 count = PathCommonPrefixA(path1, path2, out);
1280 ok(count == 3, "Expected 3, got %i\n", count);
1281 ok(!lstrcmpA(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1282 ok(!lstrcmpA(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1283 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1284 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1285
1286 /* try .. prefix */
1287 SetLastError(0xdeadbeef);
1288 lstrcpyA(path1, "one\\..two");
1289 lstrcpyA(path2, "one\\..three");
1290 lstrcpyA(out, "aaa");
1291 count = PathCommonPrefixA(path1, path2, out);
1292 ok(count == 3, "Expected 3, got %i\n", count);
1293 ok(!lstrcmpA(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1294 ok(!lstrcmpA(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1295 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1296 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1297
1298 /* try ... prefix */
1299 SetLastError(0xdeadbeef);
1300 lstrcpyA(path1, "one\\...two");
1301 lstrcpyA(path2, "one\\...three");
1302 lstrcpyA(out, "aaa");
1303 count = PathCommonPrefixA(path1, path2, out);
1304 ok(count == 3, "Expected 3, got %i\n", count);
1305 ok(!lstrcmpA(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1306 ok(!lstrcmpA(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1307 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1308 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1309
1310 /* try .\ prefix */
1311 SetLastError(0xdeadbeef);
1312 lstrcpyA(path1, "one\\.\\two");
1313 lstrcpyA(path2, "one\\.\\three");
1314 lstrcpyA(out, "aaa");
1315 count = PathCommonPrefixA(path1, path2, out);
1316 ok(count == 5, "Expected 5, got %i\n", count);
1317 ok(!lstrcmpA(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1318 ok(!lstrcmpA(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1319 ok(!lstrcmpA(out, "one\\."), "Expected one\\., got %s\n", out);
1320 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1321
1322 /* try ..\ prefix */
1323 SetLastError(0xdeadbeef);
1324 lstrcpyA(path1, "one\\..\\two");
1325 lstrcpyA(path2, "one\\..\\three");
1326 lstrcpyA(out, "aaa");
1327 count = PathCommonPrefixA(path1, path2, out);
1328 ok(count == 6, "Expected 6, got %i\n", count);
1329 ok(!lstrcmpA(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1330 ok(!lstrcmpA(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1331 ok(!lstrcmpA(out, "one\\.."), "Expected one\\.., got %s\n", out);
1332 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1333
1334 /* try ...\\ prefix */
1335 SetLastError(0xdeadbeef);
1336 lstrcpyA(path1, "one\\...\\two");
1337 lstrcpyA(path2, "one\\...\\three");
1338 lstrcpyA(out, "aaa");
1339 count = PathCommonPrefixA(path1, path2, out);
1340 ok(count == 7, "Expected 7, got %i\n", count);
1341 ok(!lstrcmpA(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1342 ok(!lstrcmpA(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1343 ok(!lstrcmpA(out, "one\\..."), "Expected one\\..., got %s\n", out);
1344 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1345
1346 /* try prefix that is not an msdn labeled prefix type */
1347 SetLastError(0xdeadbeef);
1348 lstrcpyA(path1, "same");
1349 lstrcpyA(path2, "same");
1350 lstrcpyA(out, "aaa");
1351 count = PathCommonPrefixA(path1, path2, out);
1352 ok(count == 4, "Expected 4, got %i\n", count);
1353 ok(!lstrcmpA(path1, "same"), "Expected same, got %s\n", path1);
1354 ok(!lstrcmpA(path2, "same"), "Expected same, got %s\n", path2);
1355 ok(!lstrcmpA(out, "same"), "Expected same, got %s\n", out);
1356 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1357
1358 /* try . after directory */
1359 SetLastError(0xdeadbeef);
1360 lstrcpyA(path1, "one\\mid.\\two");
1361 lstrcpyA(path2, "one\\mid.\\three");
1362 lstrcpyA(out, "aaa");
1363 count = PathCommonPrefixA(path1, path2, out);
1364 ok(count == 8, "Expected 8, got %i\n", count);
1365 ok(!lstrcmpA(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1366 ok(!lstrcmpA(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1367 ok(!lstrcmpA(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1368 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1369
1370 /* try . in the middle of a directory */
1371 SetLastError(0xdeadbeef);
1372 lstrcpyA(path1, "one\\mid.end\\two");
1373 lstrcpyA(path2, "one\\mid.end\\three");
1374 lstrcpyA(out, "aaa");
1375 count = PathCommonPrefixA(path1, path2, out);
1376 ok(count == 11, "Expected 11, got %i\n", count);
1377 ok(!lstrcmpA(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1378 ok(!lstrcmpA(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1379 ok(!lstrcmpA(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1380 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1381
1382 /* try comparing a .. with the expanded path */
1383 SetLastError(0xdeadbeef);
1384 lstrcpyA(path1, "one\\..\\two");
1385 lstrcpyA(path2, "two");
1386 lstrcpyA(out, "aaa");
1387 count = PathCommonPrefixA(path1, path2, out);
1388 ok(count == 0, "Expected 0, got %i\n", count);
1389 ok(!lstrcmpA(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1390 ok(!lstrcmpA(path2, "two"), "Expected two, got %s\n", path2);
1391 ok(!out[0], "Expected 0 length out, got %i\n", lstrlenA(out));
1392 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1393 }
1394
1395 static void test_PathUnquoteSpaces(void)
1396 {
1397 int i;
1398 for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1399 {
1400 char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1401 WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1402 WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1403
1404 PathUnquoteSpacesA(path);
1405 ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1406 TEST_PATH_UNQUOTE_SPACES[i].path, path,
1407 TEST_PATH_UNQUOTE_SPACES[i].result);
1408
1409 PathUnquoteSpacesW(pathW);
1410 ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1411 TEST_PATH_UNQUOTE_SPACES[i].path);
1412 FreeWideString(pathW);
1413 FreeWideString(resultW);
1414 HeapFree(GetProcessHeap(), 0, path);
1415 }
1416 }
1417
1418 static void test_PathGetDriveNumber(void)
1419 {
1420 static const CHAR test1A[] = "a:\\test.file";
1421 static const CHAR test2A[] = "file:////b:\\test.file";
1422 static const CHAR test3A[] = "file:///c:\\test.file";
1423 static const CHAR test4A[] = "file:\\\\c:\\test.file";
1424 static const CHAR test5A[] = "\\\\?\\C:\\dir\\file.txt";
1425 static const WCHAR test1W[] =
1426 {'a',':','\\',0};
1427 static const WCHAR test5W[] =
1428 {'\\','\\','?','\\','C',':','\\','d','i','r','\\','f','i','l','e',0};
1429 int ret;
1430
1431 SetLastError(0xdeadbeef);
1432 ret = PathGetDriveNumberA(NULL);
1433 ok(ret == -1, "got %d\n", ret);
1434 ok(GetLastError() == 0xdeadbeef, "got %d\n", GetLastError());
1435
1436 ret = PathGetDriveNumberA(test1A);
1437 ok(ret == 0, "got %d\n", ret);
1438 ret = PathGetDriveNumberW(test1W);
1439 ok(ret == 0, "got %d\n", ret);
1440 ret = PathGetDriveNumberA(test2A);
1441 ok(ret == -1, "got %d\n", ret);
1442 ret = PathGetDriveNumberA(test3A);
1443 ok(ret == -1, "got %d\n", ret);
1444 ret = PathGetDriveNumberA(test4A);
1445 ok(ret == -1, "got %d\n", ret);
1446
1447 ret = PathGetDriveNumberA(test5A);
1448 ok(ret == -1, "got %d\n", ret);
1449 ret = PathGetDriveNumberW(test5W);
1450 ok(ret == 2 || broken(ret == -1) /* winxp */, "got = %d\n", ret);
1451 }
1452
1453 static void test_PathUnExpandEnvStrings(void)
1454 {
1455 static const WCHAR sysrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
1456 static const WCHAR sysdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
1457 static const WCHAR nonpathW[] = {'p','a','t','h',0};
1458 static const char sysrootA[] = "%SystemRoot%";
1459 static const char sysdriveA[] = "%SystemDrive%";
1460 WCHAR pathW[MAX_PATH], buffW[MAX_PATH], sysdrvW[3];
1461 char path[MAX_PATH], buff[MAX_PATH], sysdrvA[3], envvarA[10];
1462 BOOL ret;
1463 UINT len;
1464
1465 if (!pPathUnExpandEnvStringsA || !pPathUnExpandEnvStringsW)
1466 {
1467 win_skip("PathUnExpandEnvStrings not available\n");
1468 return;
1469 }
1470
1471 /* something that can't be represented with env var */
1472 strcpy(path, "somepath_name");
1473 strcpy(buff, "xx");
1474 SetLastError(0xdeadbeef);
1475 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1476 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1477 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1478
1479 len = GetSystemDirectoryA(path, MAX_PATH);
1480 ok(len > 0, "failed to get sysdir\n");
1481
1482 sysdrvA[0] = path[0];
1483 strcpy(&sysdrvA[1], ":");
1484
1485 /* buffer size is not enough */
1486 strcpy(buff, "xx");
1487 SetLastError(0xdeadbeef);
1488 ret = pPathUnExpandEnvStringsA(path, buff, 5);
1489 ok(!ret && GetLastError() == 0xdeadbeef, "got %d\n", ret);
1490 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1491
1492 /* buffer size is enough to hold variable name only */
1493 strcpy(buff, "xx");
1494 SetLastError(0xdeadbeef);
1495 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(sysrootA));
1496 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1497 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1498
1499 /* enough size */
1500 buff[0] = 0;
1501 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1502 ok(ret, "got %d\n", ret);
1503 ok(!strncmp(buff, sysrootA, sizeof(sysrootA)-1), "wrong return string %s\n", buff);
1504
1505 /* expanded value occurs multiple times */
1506 /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */
1507 buff[0] = 0;
1508 strcpy(path, sysdrvA);
1509 strcat(path, sysdrvA);
1510 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1511 ok(ret, "got %d\n", ret);
1512 /* expected string */
1513 strcpy(path, sysdriveA);
1514 strcat(path, sysdrvA);
1515 ok(!strcmp(buff, path), "wrong unexpanded string %s, expected %s\n", buff, path);
1516
1517 /* now with altered variable */
1518 ret = GetEnvironmentVariableA("SystemDrive", envvarA, sizeof(envvarA));
1519 ok(ret, "got %d\n", ret);
1520
1521 ret = SetEnvironmentVariableA("SystemDrive", "WW");
1522 ok(ret, "got %d\n", ret);
1523
1524 /* variables are not cached */
1525 strcpy(path, sysdrvA);
1526 strcat(path, sysdrvA);
1527 SetLastError(0xdeadbeef);
1528 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1529 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1530
1531 ret = SetEnvironmentVariableA("SystemDrive", envvarA);
1532 ok(ret, "got %d\n", ret);
1533
1534 /* PathUnExpandEnvStringsW */
1535
1536 /* something that can't be represented with env var */
1537 lstrcpyW(pathW, nonpathW);
1538 buffW[0] = 'x'; buffW[1] = 0;
1539 SetLastError(0xdeadbeef);
1540 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
1541 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1542 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1543
1544 len = GetSystemDirectoryW(pathW, MAX_PATH);
1545 ok(len > 0, "failed to get sysdir\n");
1546
1547 sysdrvW[0] = pathW[0];
1548 sysdrvW[1] = ':';
1549 sysdrvW[2] = 0;
1550
1551 /* buffer size is not enough */
1552 buffW[0] = 'x'; buffW[1] = 0;
1553 SetLastError(0xdeadbeef);
1554 ret = pPathUnExpandEnvStringsW(pathW, buffW, 5);
1555 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1556 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1557
1558 /* buffer size is enough to hold variable name only */
1559 buffW[0] = 'x'; buffW[1] = 0;
1560 SetLastError(0xdeadbeef);
1561 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(sysrootW)/sizeof(WCHAR));
1562 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1563 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1564
1565 /* enough size */
1566 buffW[0] = 0;
1567 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
1568 ok(ret, "got %d\n", ret);
1569 ok(!memcmp(buffW, sysrootW, sizeof(sysrootW) - sizeof(WCHAR)), "wrong return string %s\n", wine_dbgstr_w(buffW));
1570
1571 /* expanded value occurs multiple times */
1572 /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */
1573 buffW[0] = 0;
1574 lstrcpyW(pathW, sysdrvW);
1575 lstrcatW(pathW, sysdrvW);
1576 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buff)/sizeof(WCHAR));
1577 ok(ret, "got %d\n", ret);
1578 /* expected string */
1579 lstrcpyW(pathW, sysdriveW);
1580 lstrcatW(pathW, sysdrvW);
1581 ok(!lstrcmpW(buffW, pathW), "wrong unexpanded string %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(pathW));
1582 }
1583
1584 static const struct {
1585 const char *path;
1586 BOOL expect;
1587 } test_path_is_relative[] = {
1588 {NULL, TRUE},
1589 {"\0", TRUE},
1590 {"test.txt", TRUE},
1591 {"\\\\folder\\test.txt", FALSE},
1592 {"file://folder/test.txt", TRUE},
1593 {"C:\\test.txt", FALSE},
1594 {"file:///C:/test.txt", TRUE}
1595 };
1596
1597 static void test_PathIsRelativeA(void)
1598 {
1599 BOOL ret;
1600 int i, num;
1601
1602 if (!pPathIsRelativeA) {
1603 win_skip("PathIsRelativeA not available\n");
1604 return;
1605 }
1606
1607 num = sizeof(test_path_is_relative) / sizeof(test_path_is_relative[0]);
1608 for (i = 0; i < num; i++) {
1609 ret = pPathIsRelativeA(test_path_is_relative[i].path);
1610 ok(ret == test_path_is_relative[i].expect,
1611 "PathIsRelativeA(\"%s\") expects %d, got %d.\n",
1612 test_path_is_relative[i].path, test_path_is_relative[i].expect, ret);
1613 }
1614 }
1615
1616 static void test_PathIsRelativeW(void)
1617 {
1618 BOOL ret;
1619 int i, num;
1620 LPWSTR path;
1621
1622 if (!pPathIsRelativeW) {
1623 win_skip("PathIsRelativeW not available\n");
1624 return;
1625 }
1626
1627 num = sizeof(test_path_is_relative) / sizeof(test_path_is_relative[0]);
1628 for (i = 0; i < num; i++) {
1629 path = GetWideString(test_path_is_relative[i].path);
1630
1631 ret = pPathIsRelativeW(path);
1632 ok(ret == test_path_is_relative[i].expect,
1633 "PathIsRelativeW(\"%s\") expects %d, got %d.\n",
1634 test_path_is_relative[i].path, test_path_is_relative[i].expect, ret);
1635
1636 FreeWideString(path);
1637 }
1638 }
1639
1640 static void test_PathStripPathA(void)
1641 {
1642 const char const_path[] = "test";
1643 char path[] = "short//path\\file.txt";
1644
1645 PathStripPathA(path);
1646 ok(!strcmp(path, "file.txt"), "path = %s\n", path);
1647
1648 /* following test should not crash */
1649 /* LavView 2013 depends on that behaviour */
1650 PathStripPathA((char*)const_path);
1651 }
1652
1653 START_TEST(path)
1654 {
1655 HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll");
1656
1657 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
1658 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
1659 win_skip("Too old shlwapi version\n");
1660 return;
1661 }
1662
1663 pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
1664 pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
1665 pPathCreateFromUrlAlloc = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlAlloc");
1666 pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1667 pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1668 pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1669 pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA");
1670 pPathUnExpandEnvStringsA = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsA");
1671 pPathUnExpandEnvStringsW = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsW");
1672 pPathIsRelativeA = (void*)GetProcAddress(hShlwapi, "PathIsRelativeA");
1673 pPathIsRelativeW = (void*)GetProcAddress(hShlwapi, "PathIsRelativeW");
1674
1675 test_PathSearchAndQualify();
1676 test_PathCreateFromUrl();
1677 test_PathIsUrl();
1678
1679 test_PathAddBackslash();
1680 test_PathMakePretty();
1681 test_PathMatchSpec();
1682
1683 test_PathIsValidCharA();
1684 test_PathIsValidCharW();
1685
1686 test_PathCombineW();
1687 test_PathCombineA();
1688 test_PathAppendA();
1689 test_PathCanonicalizeA();
1690 test_PathFindExtensionA();
1691 test_PathBuildRootA();
1692 test_PathCommonPrefixA();
1693 test_PathUnquoteSpaces();
1694 test_PathGetDriveNumber();
1695 test_PathUnExpandEnvStrings();
1696 test_PathIsRelativeA();
1697 test_PathIsRelativeW();
1698 test_PathStripPathA();
1699 }