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