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