shlwapi: Simplify UrlCombine case 2 with tests.
[wine] / dlls / shlwapi / tests / 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 }