sync shlwapi_winetest with wine 1.1.20
[reactos.git] / 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 <assert.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #include "wine/test.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "shlwapi.h"
29 #include "wininet.h"
30
31 static HMODULE hShlwapi;
32 static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD);
33 static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD);
34 static LPWSTR (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR);
35
36 /* ################ */
37
38 struct {
39 const char *url;
40 const char *path;
41 DWORD ret;
42 } TEST_PATHFROMURL[] = {
43 {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK},
44 {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK},
45 {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK},
46 {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
47 {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
48 {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK},
49 {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK},
50 {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK},
51 {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK},
52 {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK},
53 {"file://c:/foo/bar", "c:\\foo\\bar", S_OK},
54 {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK},
55 {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK},
56 {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK},
57 {"file:/foo/bar", "\\foo\\bar", S_OK},
58 {"file:/foo/bar/", "\\foo\\bar\\", S_OK},
59 {"file:foo/bar", "foo\\bar", S_OK},
60 {"file:c:/foo/bar", "c:\\foo\\bar", S_OK},
61 {"file:c|/foo/bar", "c:\\foo\\bar", S_OK},
62 {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK},
63 {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK},
64 /* {"file:////c:/foo/foo%20bar", "c:\\foo\\foo%20bar", S_OK},*/
65
66 {"c:\\foo\\bar", NULL, E_INVALIDARG},
67 {"foo/bar", NULL, E_INVALIDARG},
68 {"http://foo/bar", NULL, E_INVALIDARG},
69
70 };
71
72
73 static struct {
74 const char *path;
75 BOOL expect;
76 } TEST_PATH_IS_URL[] = {
77 {"http://foo/bar", TRUE},
78 {"c:\\foo\\bar", FALSE},
79 {"c:/foo/bar", FALSE},
80 {"foo://foo/bar", TRUE},
81 {"foo\\bar", FALSE},
82 {"foo.bar", FALSE},
83 {"bogusscheme:", TRUE},
84 {"http:partial", TRUE},
85 {"www.winehq.org", FALSE},
86 /* More examples that the user might enter as the browser start page */
87 {"winehq.org", FALSE},
88 {"ftp.winehq.org", FALSE},
89 {"http://winehq.org", TRUE},
90 {"http://www.winehq.org", TRUE},
91 {"https://winehq.org", TRUE},
92 {"https://www.winehq.org", TRUE},
93 {"ftp://winehq.org", TRUE},
94 {"ftp://ftp.winehq.org", TRUE},
95 {"file://does_not_exist.txt", TRUE},
96 {"about:blank", TRUE},
97 {"about:home", TRUE},
98 {"about:mozilla", TRUE},
99 /* scheme is case independent */
100 {"HTTP://www.winehq.org", TRUE},
101 /* a space at the start is not allowed */
102 {" http://www.winehq.org", FALSE},
103 {"", FALSE},
104 {NULL, FALSE}
105 };
106
107 struct {
108 const char *path;
109 const char *result;
110 } TEST_PATH_UNQUOTE_SPACES[] = {
111 { "abcdef", "abcdef" },
112 { "\"abcdef\"", "abcdef" },
113 { "\"abcdef", "\"abcdef" },
114 { "abcdef\"", "abcdef\"" },
115 { "\"\"abcdef\"\"", "\"abcdef\"" },
116 { "abc\"def", "abc\"def" },
117 { "\"abc\"def", "\"abc\"def" },
118 { "\"abc\"def\"", "abc\"def" },
119 { "\'abcdef\'", "\'abcdef\'" },
120 { "\"\"", "" },
121 { "\"", "" }
122 };
123
124 /* ################ */
125
126 static LPWSTR GetWideString(const char* szString)
127 {
128 LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
129
130 MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
131
132 return wszString;
133 }
134
135 static void FreeWideString(LPWSTR wszString)
136 {
137 HeapFree(GetProcessHeap(), 0, wszString);
138 }
139
140 static LPSTR strdupA(LPCSTR p)
141 {
142 LPSTR ret;
143 DWORD len = (strlen(p) + 1);
144 ret = HeapAlloc(GetProcessHeap(), 0, len);
145 memcpy(ret, p, len);
146 return ret;
147 }
148
149 /* ################ */
150
151 static void test_PathSearchAndQualify(void)
152 {
153 WCHAR path1[] = {'c',':','\\','f','o','o',0};
154 WCHAR expect1[] = {'c',':','\\','f','o','o',0};
155 WCHAR path2[] = {'c',':','f','o','o',0};
156 WCHAR c_drive[] = {'c',':',0};
157 WCHAR foo[] = {'f','o','o',0};
158 WCHAR path3[] = {'\\','f','o','o',0};
159 WCHAR winini[] = {'w','i','n','.','i','n','i',0};
160 WCHAR out[MAX_PATH];
161 WCHAR cur_dir[MAX_PATH];
162 WCHAR dot[] = {'.',0};
163
164 /* c:\foo */
165 ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
166 "PathSearchAndQualify rets 0\n");
167 ok(!lstrcmpiW(out, expect1), "strings don't match\n");
168
169 /* c:foo */
170 ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
171 "PathSearchAndQualify rets 0\n");
172 GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
173 PathAddBackslashW(cur_dir);
174 lstrcatW(cur_dir, foo);
175 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
176
177 /* foo */
178 ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
179 "PathSearchAndQualify rets 0\n");
180 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
181 PathAddBackslashW(cur_dir);
182 lstrcatW(cur_dir, foo);
183 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
184
185 /* \foo */
186 ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
187 "PathSearchAndQualify rets 0\n");
188 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
189 lstrcpyW(cur_dir + 2, path3);
190 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
191
192 /* win.ini */
193 ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
194 "PathSearchAndQualify rets 0\n");
195 if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
196 GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
197 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
198
199 }
200
201 static void test_PathCreateFromUrl(void)
202 {
203 size_t i;
204 char ret_path[INTERNET_MAX_URL_LENGTH];
205 DWORD len, ret;
206 WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
207 WCHAR *pathW, *urlW;
208 static const char url[] = "http://www.winehq.org";
209
210 /* Check ret_path = NULL */
211 len = sizeof(url);
212 ret = PathCreateFromUrlA(url, NULL, &len, 0);
213 ok ( ret == E_INVALIDARG, "got 0x%08x expected E_INVALIDARG\n", ret);
214
215 for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
216 len = INTERNET_MAX_URL_LENGTH;
217 ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
218 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url);
219 if(TEST_PATHFROMURL[i].path) {
220 ok(!lstrcmpi(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
221 ok(len == strlen(ret_path), "ret len %d from url %s\n", len, TEST_PATHFROMURL[i].url);
222 }
223 len = INTERNET_MAX_URL_LENGTH;
224 pathW = GetWideString(TEST_PATHFROMURL[i].path);
225 urlW = GetWideString(TEST_PATHFROMURL[i].url);
226 ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
227 WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
228 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
229 if(TEST_PATHFROMURL[i].path) {
230 ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
231 ok(len == lstrlenW(ret_pathW), "ret len %d from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
232 }
233 FreeWideString(urlW);
234 FreeWideString(pathW);
235 }
236 }
237
238
239 static void test_PathIsUrl(void)
240 {
241 size_t i;
242 BOOL ret;
243
244 for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
245 ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
246 ok(ret == TEST_PATH_IS_URL[i].expect,
247 "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
248 TEST_PATH_IS_URL[i].expect);
249 }
250 }
251
252 static const DWORD SHELL_charclass[] =
253 {
254 0x00000000, 0x00000000, 0x00000000, 0x00000000,
255 0x00000000, 0x00000000, 0x00000000, 0x00000000,
256 0x00000000, 0x00000000, 0x00000000, 0x00000000,
257 0x00000000, 0x00000000, 0x00000000, 0x00000000,
258 0x00000000, 0x00000000, 0x00000000, 0x00000000,
259 0x00000000, 0x00000000, 0x00000000, 0x00000000,
260 0x00000000, 0x00000000, 0x00000000, 0x00000000,
261 0x00000000, 0x00000000, 0x00000000, 0x00000000,
262 0x00000080, 0x00000100, 0x00000200, 0x00000100,
263 0x00000100, 0x00000100, 0x00000100, 0x00000100,
264 0x00000100, 0x00000100, 0x00000002, 0x00000100,
265 0x00000040, 0x00000100, 0x00000004, 0x00000000,
266 0x00000100, 0x00000100, 0x00000100, 0x00000100,
267 0x00000100, 0x00000100, 0x00000100, 0x00000100,
268 0x00000100, 0x00000100, 0x00000010, 0x00000020,
269 0x00000000, 0x00000100, 0x00000000, 0x00000001,
270 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
271 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
272 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
273 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
274 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
275 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
276 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
277 0x00000008, 0x00000100, 0x00000100, 0x00000100,
278 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
279 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
280 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
281 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
282 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
283 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
284 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
285 0x00000000, 0x00000100, 0x00000100
286 };
287
288 static void test_PathIsValidCharA(void)
289 {
290 BOOL ret;
291 unsigned int c;
292
293 for (c = 0; c < 0x7f; c++)
294 {
295 ret = pPathIsValidCharA( c, ~0U );
296 ok ( ret || !SHELL_charclass[c], "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
297 }
298
299 for (c = 0x7f; c <= 0xff; c++)
300 {
301 ret = pPathIsValidCharA( c, ~0U );
302 ok ( ret, "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
303 }
304 }
305
306 static void test_PathIsValidCharW(void)
307 {
308 BOOL ret;
309 unsigned int c;
310
311 for (c = 0; c < 0x7f; c++)
312 {
313 ret = pPathIsValidCharW( c, ~0U );
314 ok ( ret || !SHELL_charclass[c], "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
315 }
316
317 for (c = 0x007f; c <= 0xffff; c++)
318 {
319 ret = pPathIsValidCharW( c, ~0U );
320 ok ( ret, "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
321 }
322 }
323
324 static void test_PathMakePretty(void)
325 {
326 char buff[MAX_PATH];
327
328 ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
329 buff[0] = '\0';
330 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
331
332 strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
333 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
334 ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
335 "PathMakePretty: Long UC name not changed\n");
336
337 strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
338 ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
339 ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
340 "PathMakePretty: Failed but modified path\n");
341
342 strcpy(buff, "TEST");
343 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Short name failed\n");
344 ok (strcmp(buff, "Test") == 0, "PathMakePretty: 1st char lowercased %s\n", buff);
345 }
346
347 static void test_PathMatchSpec(void)
348 {
349 static const char file[] = "c:\\foo\\bar\\filename.ext";
350 static const char spec1[] = ".ext";
351 static const char spec2[] = "*.ext";
352 static const char spec3[] = "*.ext ";
353 static const char spec4[] = " *.ext";
354 static const char spec5[] = "* .ext";
355 static const char spec6[] = "*. ext";
356 static const char spec7[] = "* . ext";
357 static const char spec8[] = "*.e?t";
358 static const char spec9[] = "filename.ext";
359 static const char spec10[] = "*bar\\filename.ext";
360 static const char spec11[] = " foo; *.ext";
361 static const char spec12[] = "*.ext;*.bar";
362 static const char spec13[] = "*bar*";
363
364 ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
365 ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
366 ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
367 ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
368 todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
369 todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
370 ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
371 ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
372 ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
373 ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
374 ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
375 ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
376 ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
377 }
378
379 static void test_PathCombineW(void)
380 {
381 LPWSTR wszString, wszString2;
382 WCHAR wbuf[MAX_PATH+1], wstr1[MAX_PATH] = {'C',':','\\',0}, wstr2[MAX_PATH];
383 static const WCHAR expout[] = {'C',':','\\','A','A',0};
384 int i;
385
386 wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
387
388 /* NULL test */
389 wszString = pPathCombineW(NULL, NULL, NULL);
390 ok (wszString == NULL, "Expected a NULL return\n");
391
392 /* Some NULL */
393 wszString2[0] = 'a';
394 wszString = pPathCombineW(wszString2, NULL, NULL);
395 ok (wszString == NULL ||
396 broken(wszString[0] == 'a'), /* Win95 and some W2K */
397 "Expected a NULL return\n");
398 ok (wszString2[0] == 0 ||
399 broken(wszString2[0] == 'a'), /* Win95 and some W2K */
400 "Destination string not empty\n");
401
402 HeapFree(GetProcessHeap(), 0, wszString2);
403
404 /* overflow test */
405 wstr2[0] = wstr2[1] = wstr2[2] = 'A';
406 for (i=3; i<MAX_PATH/2; i++)
407 wstr1[i] = wstr2[i] = 'A';
408 wstr1[(MAX_PATH/2) - 1] = wstr2[MAX_PATH/2] = 0;
409 memset(wbuf, 0xbf, sizeof(wbuf));
410
411 wszString = pPathCombineW(wbuf, wstr1, wstr2);
412 ok(wszString == NULL, "Expected a NULL return\n");
413 ok(wbuf[0] == 0 ||
414 broken(wbuf[0] == 0xbfbf), /* Win95 and some W2K */
415 "Buffer contains data\n");
416
417 /* PathCombineW can be used in place */
418 wstr1[3] = 0;
419 wstr2[2] = 0;
420 ok(PathCombineW(wstr1, wstr1, wstr2) == wstr1, "Expected a wstr1 return\n");
421 ok(StrCmpW(wstr1, expout) == 0, "Unexpected PathCombine output\n");
422 }
423
424
425 #define LONG_LEN (MAX_PATH * 2)
426 #define HALF_LEN (MAX_PATH / 2 + 1)
427
428 static void test_PathCombineA(void)
429 {
430 LPSTR str;
431 char dest[MAX_PATH];
432 char too_long[LONG_LEN];
433 char one[HALF_LEN], two[HALF_LEN];
434
435 /* try NULL dest */
436 SetLastError(0xdeadbeef);
437 str = PathCombineA(NULL, "C:\\", "one\\two\\three");
438 ok(str == NULL, "Expected NULL, got %p\n", str);
439 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
440
441 /* try NULL dest and NULL directory */
442 SetLastError(0xdeadbeef);
443 str = PathCombineA(NULL, NULL, "one\\two\\three");
444 ok(str == NULL, "Expected NULL, got %p\n", str);
445 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
446
447 /* try all NULL*/
448 SetLastError(0xdeadbeef);
449 str = PathCombineA(NULL, NULL, NULL);
450 ok(str == NULL, "Expected NULL, got %p\n", str);
451 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
452
453 /* try NULL file part */
454 SetLastError(0xdeadbeef);
455 lstrcpyA(dest, "control");
456 str = PathCombineA(dest, "C:\\", NULL);
457 ok(str == dest, "Expected str == dest, got %p\n", str);
458 ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
459 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
460
461 /* try empty file part */
462 SetLastError(0xdeadbeef);
463 lstrcpyA(dest, "control");
464 str = PathCombineA(dest, "C:\\", "");
465 ok(str == dest, "Expected str == dest, got %p\n", str);
466 ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
467 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
468
469 /* try empty directory and file part */
470 SetLastError(0xdeadbeef);
471 lstrcpyA(dest, "control");
472 str = PathCombineA(dest, "", "");
473 ok(str == dest, "Expected str == dest, got %p\n", str);
474 ok(!lstrcmp(str, "\\") ||
475 broken(!lstrcmp(str, "control")), /* Win95 and some W2K */
476 "Expected \\, got %s\n", str);
477 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
478
479 /* try NULL directory */
480 SetLastError(0xdeadbeef);
481 lstrcpyA(dest, "control");
482 str = PathCombineA(dest, NULL, "one\\two\\three");
483 ok(str == dest, "Expected str == dest, got %p\n", str);
484 ok(!lstrcmp(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
485 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
486
487 /* try NULL directory and empty file part */
488 SetLastError(0xdeadbeef);
489 lstrcpyA(dest, "control");
490 str = PathCombineA(dest, NULL, "");
491 ok(str == dest, "Expected str == dest, got %p\n", str);
492 ok(!lstrcmp(str, "\\") ||
493 broken(!lstrcmp(str, "one\\two\\three")), /* Win95 and some W2K */
494 "Expected \\, got %s\n", str);
495 ok(GetLastError() == 0xdeadbeef ||
496 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win95 */
497 "Expected 0xdeadbeef, got %d\n", GetLastError());
498
499 /* try NULL directory and file part */
500 SetLastError(0xdeadbeef);
501 lstrcpyA(dest, "control");
502 str = PathCombineA(dest, NULL, NULL);
503 ok(str == NULL ||
504 broken(str != NULL), /* Win95 and some W2K */
505 "Expected str == NULL, got %p\n", str);
506 ok(lstrlenA(dest) == 0 ||
507 broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */
508 "Expected 0 length, got %i\n", lstrlenA(dest));
509 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
510
511 /* try directory without backslash */
512 SetLastError(0xdeadbeef);
513 lstrcpyA(dest, "control");
514 str = PathCombineA(dest, "C:", "one\\two\\three");
515 ok(str == dest, "Expected str == dest, got %p\n", str);
516 ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
517 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
518
519 /* try directory with backslash */
520 SetLastError(0xdeadbeef);
521 lstrcpyA(dest, "control");
522 str = PathCombineA(dest, "C:\\", "one\\two\\three");
523 ok(str == dest, "Expected str == dest, got %p\n", str);
524 ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
525 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
526
527 /* try directory with backslash and file with prepended backslash */
528 SetLastError(0xdeadbeef);
529 lstrcpyA(dest, "control");
530 str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
531 ok(str == dest, "Expected str == dest, got %p\n", str);
532 ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
533 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
534
535 /* try previous test, with backslash appended as well */
536 SetLastError(0xdeadbeef);
537 lstrcpyA(dest, "control");
538 str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
539 ok(str == dest, "Expected str == dest, got %p\n", str);
540 ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
541 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
542
543 /* try a relative directory */
544 SetLastError(0xdeadbeef);
545 lstrcpyA(dest, "control");
546 str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
547 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
548 /* Vista fails which probably makes sense as PathCombineA expects an absolute dir */
549 if (str)
550 {
551 ok(str == dest, "Expected str == dest, got %p\n", str);
552 ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
553 }
554
555 /* try forward slashes */
556 SetLastError(0xdeadbeef);
557 lstrcpyA(dest, "control");
558 str = PathCombineA(dest, "C:\\", "one/two/three\\");
559 ok(str == dest, "Expected str == dest, got %p\n", str);
560 ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
561 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
562
563 /* try a really weird directory */
564 SetLastError(0xdeadbeef);
565 lstrcpyA(dest, "control");
566 str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
567 ok(str == dest, "Expected str == dest, got %p\n", str);
568 ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
569 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
570
571 /* try periods */
572 SetLastError(0xdeadbeef);
573 lstrcpyA(dest, "control");
574 str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
575 ok(str == dest, "Expected str == dest, got %p\n", str);
576 ok(!lstrcmp(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
577 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
578
579 /* try .. as file */
580 /* try forward slashes */
581 SetLastError(0xdeadbeef);
582 lstrcpyA(dest, "control");
583 str = PathCombineA(dest, "C:\\", "..");
584 ok(str == dest, "Expected str == dest, got %p\n", str);
585 ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
586 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
587
588 memset(too_long, 'a', LONG_LEN);
589 too_long[LONG_LEN - 1] = '\0';
590
591 /* try a file longer than MAX_PATH */
592 SetLastError(0xdeadbeef);
593 lstrcpyA(dest, "control");
594 str = PathCombineA(dest, "C:\\", too_long);
595 ok(str == NULL, "Expected str == NULL, got %p\n", str);
596 ok(lstrlenA(dest) == 0 ||
597 broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */
598 "Expected 0 length, got %i\n", lstrlenA(dest));
599 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
600
601 /* try a directory longer than MAX_PATH */
602 SetLastError(0xdeadbeef);
603 lstrcpyA(dest, "control");
604 str = PathCombineA(dest, too_long, "one\\two\\three");
605 ok(str == NULL, "Expected str == NULL, got %p\n", str);
606 ok(lstrlenA(dest) == 0 ||
607 broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */
608 "Expected 0 length, got %i\n", lstrlenA(dest));
609 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
610
611 memset(one, 'b', HALF_LEN);
612 memset(two, 'c', HALF_LEN);
613 one[HALF_LEN - 1] = '\0';
614 two[HALF_LEN - 1] = '\0';
615
616 /* destination string is longer than MAX_PATH, but not the constituent parts */
617 SetLastError(0xdeadbeef);
618 lstrcpyA(dest, "control");
619 str = PathCombineA(dest, one, two);
620 ok(str == NULL, "Expected str == NULL, got %p\n", str);
621 ok(lstrlenA(dest) == 0 ||
622 broken(!lstrcmp(dest, "control")), /* Win95 and some W2K */
623 "Expected 0 length, got %i\n", lstrlenA(dest));
624 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
625 }
626
627 static void test_PathAddBackslash(void)
628 {
629 LPSTR str;
630 char path[MAX_PATH];
631 char too_long[LONG_LEN];
632
633 /* try a NULL path */
634 SetLastError(0xdeadbeef);
635 str = PathAddBackslashA(NULL);
636 ok(str == NULL, "Expected str == NULL, got %p\n", str);
637 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
638
639 /* try an empty path */
640 path[0] = '\0';
641 SetLastError(0xdeadbeef);
642 str = PathAddBackslashA(path);
643 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
644 ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
645 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
646
647 /* try a relative path */
648 lstrcpyA(path, "one\\two");
649 SetLastError(0xdeadbeef);
650 str = PathAddBackslashA(path);
651 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
652 ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
653 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
654
655 /* try periods */
656 lstrcpyA(path, "one\\..\\two");
657 SetLastError(0xdeadbeef);
658 str = PathAddBackslashA(path);
659 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
660 ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
661 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
662
663 /* try just a space */
664 lstrcpyA(path, " ");
665 SetLastError(0xdeadbeef);
666 str = PathAddBackslashA(path);
667 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
668 ok(!lstrcmp(path, " \\"), "Expected \\, got %s\n", path);
669 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
670
671 /* path already has backslash */
672 lstrcpyA(path, "C:\\one\\");
673 SetLastError(0xdeadbeef);
674 str = PathAddBackslashA(path);
675 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
676 ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
677 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
678
679 memset(too_long, 'a', LONG_LEN);
680 too_long[LONG_LEN - 1] = '\0';
681
682 /* path is longer than MAX_PATH */
683 SetLastError(0xdeadbeef);
684 str = PathAddBackslashA(too_long);
685 ok(str == NULL, "Expected str == NULL, got %p\n", str);
686 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
687 }
688
689 static void test_PathAppendA(void)
690 {
691 char path[MAX_PATH];
692 char too_long[LONG_LEN];
693 char one[HALF_LEN], two[HALF_LEN];
694 BOOL res;
695
696 lstrcpy(path, "C:\\one");
697
698 /* try NULL pszMore */
699 SetLastError(0xdeadbeef);
700 res = PathAppendA(path, NULL);
701 ok(!res, "Expected failure\n");
702 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
703 ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
704
705 /* try empty pszMore */
706 SetLastError(0xdeadbeef);
707 res = PathAppendA(path, "");
708 ok(res, "Expected success\n");
709 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
710 ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
711
712 /* try NULL pszPath */
713 SetLastError(0xdeadbeef);
714 res = PathAppendA(NULL, "two\\three");
715 ok(!res, "Expected failure\n");
716 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
717
718 /* try empty pszPath */
719 path[0] = '\0';
720 SetLastError(0xdeadbeef);
721 res = PathAppendA(path, "two\\three");
722 ok(res, "Expected success\n");
723 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
724 ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
725
726 /* try empty pszPath and empty pszMore */
727 path[0] = '\0';
728 SetLastError(0xdeadbeef);
729 res = PathAppendA(path, "");
730 ok(res, "Expected success\n");
731 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
732 ok(!lstrcmp(path, "\\"), "Expected \\, got %s\n", path);
733
734 /* try legit params */
735 lstrcpy(path, "C:\\one");
736 SetLastError(0xdeadbeef);
737 res = PathAppendA(path, "two\\three");
738 ok(res, "Expected success\n");
739 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
740 ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
741
742 /* try pszPath with backslash after it */
743 lstrcpy(path, "C:\\one\\");
744 SetLastError(0xdeadbeef);
745 res = PathAppendA(path, "two\\three");
746 ok(res, "Expected success\n");
747 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
748 ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
749
750 /* try pszMore with backslash before it */
751 lstrcpy(path, "C:\\one");
752 SetLastError(0xdeadbeef);
753 res = PathAppendA(path, "\\two\\three");
754 ok(res, "Expected success\n");
755 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
756 ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
757
758 /* try pszMore with backslash after it */
759 lstrcpy(path, "C:\\one");
760 SetLastError(0xdeadbeef);
761 res = PathAppendA(path, "two\\three\\");
762 ok(res, "Expected success\n");
763 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
764 ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
765
766 /* try spaces in pszPath */
767 lstrcpy(path, "C: \\ one ");
768 SetLastError(0xdeadbeef);
769 res = PathAppendA(path, "two\\three");
770 ok(res, "Expected success\n");
771 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
772 ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
773
774 /* try spaces in pszMore */
775 lstrcpy(path, "C:\\one");
776 SetLastError(0xdeadbeef);
777 res = PathAppendA(path, " two \\ three ");
778 ok(res, "Expected success\n");
779 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
780 ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
781
782 /* pszPath is too long */
783 memset(too_long, 'a', LONG_LEN);
784 too_long[LONG_LEN - 1] = '\0';
785 SetLastError(0xdeadbeef);
786 res = PathAppendA(too_long, "two\\three");
787 ok(!res, "Expected failure\n");
788 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
789 ok(lstrlen(too_long) == 0 ||
790 broken(lstrlen(too_long) == (LONG_LEN - 1)), /* Win95 and some W2K */
791 "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
792
793 /* pszMore is too long */
794 lstrcpy(path, "C:\\one");
795 memset(too_long, 'a', LONG_LEN);
796 too_long[LONG_LEN - 1] = '\0';
797 SetLastError(0xdeadbeef);
798 res = PathAppendA(path, too_long);
799 ok(!res, "Expected failure\n");
800 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
801 ok(lstrlen(path) == 0 ||
802 broken(!lstrcmp(path, "C:\\one")), /* Win95 and some W2K */
803 "Expected length of path to be zero, got %i\n", lstrlen(path));
804
805 /* both params combined are too long */
806 memset(one, 'a', HALF_LEN);
807 one[HALF_LEN - 1] = '\0';
808 memset(two, 'b', HALF_LEN);
809 two[HALF_LEN - 1] = '\0';
810 SetLastError(0xdeadbeef);
811 res = PathAppendA(one, two);
812 ok(!res, "Expected failure\n");
813 ok(lstrlen(one) == 0 ||
814 broken(lstrlen(one) == (HALF_LEN - 1)), /* Win95 and some W2K */
815 "Expected length of one to be zero, got %i\n", lstrlen(one));
816 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
817 }
818
819 static void test_PathCanonicalizeA(void)
820 {
821 char dest[LONG_LEN + MAX_PATH];
822 char too_long[LONG_LEN];
823 BOOL res;
824
825 /* try a NULL source */
826 lstrcpy(dest, "test");
827 SetLastError(0xdeadbeef);
828 res = PathCanonicalizeA(dest, NULL);
829 ok(!res, "Expected failure\n");
830 ok(GetLastError() == ERROR_INVALID_PARAMETER,
831 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
832 ok(dest[0] == 0 || !lstrcmp(dest, "test"),
833 "Expected either an empty string (Vista) or test, got %s\n", dest);
834
835 /* try an empty source */
836 lstrcpy(dest, "test");
837 SetLastError(0xdeadbeef);
838 res = PathCanonicalizeA(dest, "");
839 ok(res, "Expected success\n");
840 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
841 ok(!lstrcmp(dest, "\\") ||
842 broken(!lstrcmp(dest, "test")), /* Win95 and some W2K */
843 "Expected \\, got %s\n", dest);
844
845 /* try a NULL dest */
846 SetLastError(0xdeadbeef);
847 res = PathCanonicalizeA(NULL, "C:\\");
848 ok(!res, "Expected failure\n");
849 ok(GetLastError() == ERROR_INVALID_PARAMETER,
850 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
851
852 /* try empty dest */
853 dest[0] = '\0';
854 SetLastError(0xdeadbeef);
855 res = PathCanonicalizeA(dest, "C:\\");
856 ok(res, "Expected success\n");
857 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
858 ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
859
860 /* try non-empty dest */
861 lstrcpy(dest, "test");
862 SetLastError(0xdeadbeef);
863 res = PathCanonicalizeA(dest, "C:\\");
864 ok(res, "Expected success\n");
865 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
866 ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
867
868 /* try a space for source */
869 lstrcpy(dest, "test");
870 SetLastError(0xdeadbeef);
871 res = PathCanonicalizeA(dest, " ");
872 ok(res, "Expected success\n");
873 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
874 ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
875
876 /* try a relative path */
877 lstrcpy(dest, "test");
878 SetLastError(0xdeadbeef);
879 res = PathCanonicalizeA(dest, "one\\two");
880 ok(res, "Expected success\n");
881 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
882 ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
883
884 /* try current dir and previous dir */
885 lstrcpy(dest, "test");
886 SetLastError(0xdeadbeef);
887 res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
888 ok(res, "Expected success\n");
889 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
890 ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
891
892 /* try simple forward slashes */
893 lstrcpy(dest, "test");
894 SetLastError(0xdeadbeef);
895 res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
896 ok(res, "Expected success\n");
897 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
898 ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
899 "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
900
901 /* try simple forward slashes with same dir */
902 lstrcpy(dest, "test");
903 SetLastError(0xdeadbeef);
904 res = PathCanonicalizeA(dest, "C:\\one/.\\two");
905 ok(res, "Expected success\n");
906 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
907 ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
908
909 /* try simple forward slashes with change dir */
910 lstrcpy(dest, "test");
911 SetLastError(0xdeadbeef);
912 res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
913 ok(res, "Expected success\n");
914 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
915 ok(!lstrcmp(dest, "C:\\one/.") ||
916 !lstrcmp(dest, "C:\\one/"), /* Vista */
917 "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest);
918
919 /* try forward slashes with change dirs
920 * NOTE: if there is a forward slash in between two backslashes,
921 * everything in between the two backslashes is considered on dir
922 */
923 lstrcpy(dest, "test");
924 SetLastError(0xdeadbeef);
925 res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
926 ok(res, "Expected success\n");
927 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
928 ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
929
930 /* try src is too long */
931 memset(too_long, 'a', LONG_LEN);
932 too_long[LONG_LEN - 1] = '\0';
933 lstrcpy(dest, "test");
934 SetLastError(0xdeadbeef);
935 res = PathCanonicalizeA(dest, too_long);
936 ok(!res ||
937 broken(res), /* Win95, some W2K and XP-SP1 */
938 "Expected failure\n");
939 todo_wine
940 {
941 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */,
942 "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
943 }
944 ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
945 }
946
947 static void test_PathFindExtensionA(void)
948 {
949 LPSTR ext;
950 char path[MAX_PATH];
951 char too_long[LONG_LEN];
952
953 /* try a NULL path */
954 SetLastError(0xdeadbeef);
955 ext = PathFindExtensionA(NULL);
956 ok(ext == NULL, "Expected NULL, got %p\n", ext);
957 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
958
959 /* try an empty path */
960 path[0] = '\0';
961 SetLastError(0xdeadbeef);
962 ext = PathFindExtensionA(path);
963 ok(ext == path, "Expected ext == path, got %p\n", ext);
964 ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
965 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
966
967 /* try a path without an extension */
968 lstrcpy(path, "file");
969 SetLastError(0xdeadbeef);
970 ext = PathFindExtensionA(path);
971 ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
972 ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
973 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
974
975 /* try a path with an extension */
976 lstrcpy(path, "file.txt");
977 SetLastError(0xdeadbeef);
978 ext = PathFindExtensionA(path);
979 ok(ext == path + lstrlen("file"),
980 "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
981 ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
982 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
983
984 /* try a path with two extensions */
985 lstrcpy(path, "file.txt.doc");
986 SetLastError(0xdeadbeef);
987 ext = PathFindExtensionA(path);
988 ok(ext == path + lstrlen("file.txt"),
989 "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
990 ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
991 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
992
993 /* try a path longer than MAX_PATH without an extension*/
994 memset(too_long, 'a', LONG_LEN);
995 too_long[LONG_LEN - 1] = '\0';
996 SetLastError(0xdeadbeef);
997 ext = PathFindExtensionA(too_long);
998 ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
999 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1000
1001 /* try a path longer than MAX_PATH with an extension*/
1002 memset(too_long, 'a', LONG_LEN);
1003 too_long[LONG_LEN - 1] = '\0';
1004 lstrcpy(too_long + 300, ".abcde");
1005 too_long[lstrlen(too_long)] = 'a';
1006 SetLastError(0xdeadbeef);
1007 ext = PathFindExtensionA(too_long);
1008 ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1009 ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
1010 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1011 }
1012
1013 static void test_PathBuildRootA(void)
1014 {
1015 LPSTR root;
1016 char path[10];
1017 char root_expected[26][4];
1018 char drive;
1019 int j;
1020
1021 /* set up the expected paths */
1022 for (drive = 'A'; drive <= 'Z'; drive++)
1023 sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1024
1025 /* test the expected values */
1026 for (j = 0; j < 26; j++)
1027 {
1028 SetLastError(0xdeadbeef);
1029 lstrcpy(path, "aaaaaaaaa");
1030 root = PathBuildRootA(path, j);
1031 ok(root == path, "Expected root == path, got %p\n", root);
1032 ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1033 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1034 }
1035
1036 /* test a negative drive number */
1037 SetLastError(0xdeadbeef);
1038 lstrcpy(path, "aaaaaaaaa");
1039 root = PathBuildRootA(path, -1);
1040 ok(root == path, "Expected root == path, got %p\n", root);
1041 ok(!lstrcmp(path, "aaaaaaaaa") ||
1042 lstrlenA(path) == 0, /* Vista */
1043 "Expected aaaaaaaaa or empty string, got %s\n", path);
1044 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1045
1046 /* test a drive number greater than 25 */
1047 SetLastError(0xdeadbeef);
1048 lstrcpy(path, "aaaaaaaaa");
1049 root = PathBuildRootA(path, 26);
1050 ok(root == path, "Expected root == path, got %p\n", root);
1051 ok(!lstrcmp(path, "aaaaaaaaa") ||
1052 lstrlenA(path) == 0, /* Vista */
1053 "Expected aaaaaaaaa or empty string, got %s\n", path);
1054 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1055
1056 /* length of path is less than 4 */
1057 SetLastError(0xdeadbeef);
1058 lstrcpy(path, "aa");
1059 root = PathBuildRootA(path, 0);
1060 ok(root == path, "Expected root == path, got %p\n", root);
1061 ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1062 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1063
1064 /* path is NULL */
1065 SetLastError(0xdeadbeef);
1066 root = PathBuildRootA(NULL, 0);
1067 ok(root == NULL, "Expected root == NULL, got %p\n", root);
1068 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1069 }
1070
1071 static void test_PathCommonPrefixA(void)
1072 {
1073 char path1[MAX_PATH], path2[MAX_PATH];
1074 char out[MAX_PATH];
1075 int count;
1076
1077 /* test NULL path1 */
1078 SetLastError(0xdeadbeef);
1079 lstrcpy(path2, "C:\\");
1080 lstrcpy(out, "aaa");
1081 count = PathCommonPrefixA(NULL, path2, out);
1082 ok(count == 0, "Expected 0, got %i\n", count);
1083 todo_wine
1084 {
1085 ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1086 }
1087 ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1088 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1089
1090 /* test NULL path2 */
1091 SetLastError(0xdeadbeef);
1092 lstrcpy(path1, "C:\\");
1093 lstrcpy(out, "aaa");
1094 count = PathCommonPrefixA(path1, NULL, out);
1095 ok(count == 0, "Expected 0, got %i\n", count);
1096 todo_wine
1097 {
1098 ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1099 }
1100 ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1101 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1102
1103 /* test empty path1 */
1104 SetLastError(0xdeadbeef);
1105 path1[0] = '\0';
1106 lstrcpy(path2, "C:\\");
1107 lstrcpy(out, "aaa");
1108 count = PathCommonPrefixA(path1, path2, out);
1109 ok(count == 0, "Expected 0, got %i\n", count);
1110 ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1111 ok(lstrlen(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1112 ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1113 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1114
1115 /* test empty path1 */
1116 SetLastError(0xdeadbeef);
1117 path2[0] = '\0';
1118 lstrcpy(path1, "C:\\");
1119 lstrcpy(out, "aaa");
1120 count = PathCommonPrefixA(path1, path2, out);
1121 ok(count == 0, "Expected 0, got %i\n", count);
1122 ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1123 ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1124 ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1125 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1126
1127 /* paths are legit, out is NULL */
1128 SetLastError(0xdeadbeef);
1129 lstrcpy(path1, "C:\\");
1130 lstrcpy(path2, "C:\\");
1131 count = PathCommonPrefixA(path1, path2, NULL);
1132 ok(count == 3, "Expected 3, got %i\n", count);
1133 ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1134 ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1135 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1136
1137 /* all parameters legit */
1138 SetLastError(0xdeadbeef);
1139 lstrcpy(path1, "C:\\");
1140 lstrcpy(path2, "C:\\");
1141 lstrcpy(out, "aaa");
1142 count = PathCommonPrefixA(path1, path2, out);
1143 ok(count == 3, "Expected 3, got %i\n", count);
1144 ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1145 ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1146 ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1147 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1148
1149 /* path1 and path2 not the same, but common prefix */
1150 SetLastError(0xdeadbeef);
1151 lstrcpy(path1, "C:\\one\\two");
1152 lstrcpy(path2, "C:\\one\\three");
1153 lstrcpy(out, "aaa");
1154 count = PathCommonPrefixA(path1, path2, out);
1155 ok(count == 6, "Expected 6, got %i\n", count);
1156 ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1157 ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1158 ok(!lstrcmp(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1159 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1160
1161 /* try . prefix */
1162 SetLastError(0xdeadbeef);
1163 lstrcpy(path1, "one\\.two");
1164 lstrcpy(path2, "one\\.three");
1165 lstrcpy(out, "aaa");
1166 count = PathCommonPrefixA(path1, path2, out);
1167 ok(count == 3, "Expected 3, got %i\n", count);
1168 ok(!lstrcmp(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1169 ok(!lstrcmp(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1170 ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1171 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1172
1173 /* try .. prefix */
1174 SetLastError(0xdeadbeef);
1175 lstrcpy(path1, "one\\..two");
1176 lstrcpy(path2, "one\\..three");
1177 lstrcpy(out, "aaa");
1178 count = PathCommonPrefixA(path1, path2, out);
1179 ok(count == 3, "Expected 3, got %i\n", count);
1180 ok(!lstrcmp(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1181 ok(!lstrcmp(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1182 ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1183 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1184
1185 /* try ... prefix */
1186 SetLastError(0xdeadbeef);
1187 lstrcpy(path1, "one\\...two");
1188 lstrcpy(path2, "one\\...three");
1189 lstrcpy(out, "aaa");
1190 count = PathCommonPrefixA(path1, path2, out);
1191 ok(count == 3, "Expected 3, got %i\n", count);
1192 ok(!lstrcmp(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1193 ok(!lstrcmp(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1194 ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1195 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1196
1197 /* try .\ prefix */
1198 SetLastError(0xdeadbeef);
1199 lstrcpy(path1, "one\\.\\two");
1200 lstrcpy(path2, "one\\.\\three");
1201 lstrcpy(out, "aaa");
1202 count = PathCommonPrefixA(path1, path2, out);
1203 ok(count == 5, "Expected 5, got %i\n", count);
1204 ok(!lstrcmp(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1205 ok(!lstrcmp(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1206 ok(!lstrcmp(out, "one\\."), "Expected one\\., got %s\n", out);
1207 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1208
1209 /* try ..\ prefix */
1210 SetLastError(0xdeadbeef);
1211 lstrcpy(path1, "one\\..\\two");
1212 lstrcpy(path2, "one\\..\\three");
1213 lstrcpy(out, "aaa");
1214 count = PathCommonPrefixA(path1, path2, out);
1215 ok(count == 6, "Expected 6, got %i\n", count);
1216 ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1217 ok(!lstrcmp(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1218 ok(!lstrcmp(out, "one\\.."), "Expected one\\.., got %s\n", out);
1219 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1220
1221 /* try ...\\ prefix */
1222 SetLastError(0xdeadbeef);
1223 lstrcpy(path1, "one\\...\\two");
1224 lstrcpy(path2, "one\\...\\three");
1225 lstrcpy(out, "aaa");
1226 count = PathCommonPrefixA(path1, path2, out);
1227 ok(count == 7, "Expected 7, got %i\n", count);
1228 ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1229 ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1230 ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1231 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1232
1233 /* try prefix that is not an msdn labeled prefix type */
1234 SetLastError(0xdeadbeef);
1235 lstrcpy(path1, "same");
1236 lstrcpy(path2, "same");
1237 lstrcpy(out, "aaa");
1238 count = PathCommonPrefixA(path1, path2, out);
1239 ok(count == 4, "Expected 4, got %i\n", count);
1240 ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1241 ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1242 ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1243 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1244
1245 /* try . after directory */
1246 SetLastError(0xdeadbeef);
1247 lstrcpy(path1, "one\\mid.\\two");
1248 lstrcpy(path2, "one\\mid.\\three");
1249 lstrcpy(out, "aaa");
1250 count = PathCommonPrefixA(path1, path2, out);
1251 ok(count == 8, "Expected 8, got %i\n", count);
1252 ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1253 ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1254 ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1255 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1256
1257 /* try . in the middle of a directory */
1258 SetLastError(0xdeadbeef);
1259 lstrcpy(path1, "one\\mid.end\\two");
1260 lstrcpy(path2, "one\\mid.end\\three");
1261 lstrcpy(out, "aaa");
1262 count = PathCommonPrefixA(path1, path2, out);
1263 ok(count == 11, "Expected 11, got %i\n", count);
1264 ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1265 ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1266 ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1267 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1268
1269 /* try comparing a .. with the expanded path */
1270 SetLastError(0xdeadbeef);
1271 lstrcpy(path1, "one\\..\\two");
1272 lstrcpy(path2, "two");
1273 lstrcpy(out, "aaa");
1274 count = PathCommonPrefixA(path1, path2, out);
1275 ok(count == 0, "Expected 0, got %i\n", count);
1276 ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1277 ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1278 ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1279 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1280 }
1281
1282 static void test_PathUnquoteSpaces(void)
1283 {
1284 int i;
1285 for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1286 {
1287 char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1288 WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1289 WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1290
1291 PathUnquoteSpacesA(path);
1292 ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1293 TEST_PATH_UNQUOTE_SPACES[i].path, path,
1294 TEST_PATH_UNQUOTE_SPACES[i].result);
1295
1296 PathUnquoteSpacesW(pathW);
1297 ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1298 TEST_PATH_UNQUOTE_SPACES[i].path);
1299 FreeWideString(pathW);
1300 FreeWideString(resultW);
1301 HeapFree(GetProcessHeap(), 0, path);
1302 }
1303 }
1304
1305 /* ################ */
1306
1307 START_TEST(path)
1308 {
1309 hShlwapi = GetModuleHandleA("shlwapi.dll");
1310
1311 test_PathSearchAndQualify();
1312 test_PathCreateFromUrl();
1313 test_PathIsUrl();
1314
1315 test_PathAddBackslash();
1316 test_PathMakePretty();
1317 test_PathMatchSpec();
1318
1319 /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1320 * ordinal number in some native versions. Check this to prevent a crash.
1321 */
1322 pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1323 if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1324 {
1325 test_PathIsValidCharA();
1326
1327 pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1328 if (pPathIsValidCharW) test_PathIsValidCharW();
1329 }
1330
1331 pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1332 if (pPathCombineW)
1333 test_PathCombineW();
1334
1335 test_PathCombineA();
1336 test_PathAppendA();
1337 test_PathCanonicalizeA();
1338 test_PathFindExtensionA();
1339 test_PathBuildRootA();
1340 test_PathCommonPrefixA();
1341 test_PathUnquoteSpaces();
1342 }