user32/tests: Fix some window test failures on various Windows platforms.
[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, "Expected a NULL return\n");
396     ok (wszString2[0] == 0, "Destination string not empty\n");
397
398     HeapFree(GetProcessHeap(), 0, wszString2);
399
400     /* overflow test */
401     wstr2[0] = wstr2[1] = wstr2[2] = 'A';
402     for (i=3; i<MAX_PATH/2; i++)
403         wstr1[i] = wstr2[i] = 'A';
404     wstr1[(MAX_PATH/2) - 1] = wstr2[MAX_PATH/2] = 0;
405     memset(wbuf, 0xbf, sizeof(wbuf));
406
407     wszString = pPathCombineW(wbuf, wstr1, wstr2);
408     ok(wszString == NULL, "Expected a NULL return\n");
409     ok(wbuf[0] == 0, "Buffer contains data\n");
410
411     /* PathCombineW can be used in place */
412     wstr1[3] = 0;
413     wstr2[2] = 0;
414     ok(PathCombineW(wstr1, wstr1, wstr2) == wstr1, "Expected a wstr1 return\n");
415     ok(StrCmpW(wstr1, expout) == 0, "Unexpected PathCombine output\n");
416 }
417
418
419 #define LONG_LEN (MAX_PATH * 2)
420 #define HALF_LEN (MAX_PATH / 2 + 1)
421
422 static void test_PathCombineA(void)
423 {
424     LPSTR str;
425     char dest[MAX_PATH];
426     char too_long[LONG_LEN];
427     char one[HALF_LEN], two[HALF_LEN];
428
429     /* try NULL dest */
430     SetLastError(0xdeadbeef);
431     str = PathCombineA(NULL, "C:\\", "one\\two\\three");
432     ok(str == NULL, "Expected NULL, got %p\n", str);
433     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
434
435     /* try NULL dest and NULL directory */
436     SetLastError(0xdeadbeef);
437     str = PathCombineA(NULL, NULL, "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 all NULL*/
442     SetLastError(0xdeadbeef);
443     str = PathCombineA(NULL, NULL, NULL);
444     ok(str == NULL, "Expected NULL, got %p\n", str);
445     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
446
447     /* try NULL file part */
448     SetLastError(0xdeadbeef);
449     lstrcpyA(dest, "control");
450     str = PathCombineA(dest, "C:\\", NULL);
451     ok(str == dest, "Expected str == dest, got %p\n", str);
452     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
453     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
454
455     /* try empty file part */
456     SetLastError(0xdeadbeef);
457     lstrcpyA(dest, "control");
458     str = PathCombineA(dest, "C:\\", "");
459     ok(str == dest, "Expected str == dest, got %p\n", str);
460     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
461     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
462
463     /* try empty directory and file part */
464     SetLastError(0xdeadbeef);
465     lstrcpyA(dest, "control");
466     str = PathCombineA(dest, "", "");
467     ok(str == dest, "Expected str == dest, got %p\n", str);
468     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
469     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
470
471     /* try NULL directory */
472     SetLastError(0xdeadbeef);
473     lstrcpyA(dest, "control");
474     str = PathCombineA(dest, NULL, "one\\two\\three");
475     ok(str == dest, "Expected str == dest, got %p\n", str);
476     ok(!lstrcmp(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
477     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
478
479     /* try NULL directory and empty file part */
480     SetLastError(0xdeadbeef);
481     lstrcpyA(dest, "control");
482     str = PathCombineA(dest, NULL, "");
483     ok(str == dest, "Expected str == dest, got %p\n", str);
484     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
485     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
486
487     /* try NULL directory and file part */
488     SetLastError(0xdeadbeef);
489     lstrcpyA(dest, "control");
490     str = PathCombineA(dest, NULL, NULL);
491     ok(str == NULL, "Expected str == NULL, got %p\n", str);
492     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
493     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
494
495     /* try directory without backslash */
496     SetLastError(0xdeadbeef);
497     lstrcpyA(dest, "control");
498     str = PathCombineA(dest, "C:", "one\\two\\three");
499     ok(str == dest, "Expected str == dest, got %p\n", str);
500     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
501     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
502
503     /* try directory with backslash */
504     SetLastError(0xdeadbeef);
505     lstrcpyA(dest, "control");
506     str = PathCombineA(dest, "C:\\", "one\\two\\three");
507     ok(str == dest, "Expected str == dest, got %p\n", str);
508     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
509     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
510
511     /* try directory with backslash and file with prepended 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 previous test, with backslash appended as well */
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 a relative directory */
528     SetLastError(0xdeadbeef);
529     lstrcpyA(dest, "control");
530     str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
531     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
532     /* Vista fails which probably makes sense as PathCombineA expects an absolute dir */
533     if (str)
534     {
535         ok(str == dest, "Expected str == dest, got %p\n", str);
536         ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
537     }
538
539     /* try forward slashes */
540     SetLastError(0xdeadbeef);
541     lstrcpyA(dest, "control");
542     str = PathCombineA(dest, "C:\\", "one/two/three\\");
543     ok(str == dest, "Expected str == dest, got %p\n", str);
544     ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
545     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
546
547     /* try a really weird directory */
548     SetLastError(0xdeadbeef);
549     lstrcpyA(dest, "control");
550     str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
551     ok(str == dest, "Expected str == dest, got %p\n", str);
552     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
553     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
554
555     /* try periods */
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:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
561     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
562
563     /* try .. as file */
564     /* try forward slashes */
565     SetLastError(0xdeadbeef);
566     lstrcpyA(dest, "control");
567     str = PathCombineA(dest, "C:\\", "..");
568     ok(str == dest, "Expected str == dest, got %p\n", str);
569     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
570     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
571
572     memset(too_long, 'a', LONG_LEN);
573     too_long[LONG_LEN - 1] = '\0';
574
575     /* try a file longer than MAX_PATH */
576     SetLastError(0xdeadbeef);
577     lstrcpyA(dest, "control");
578     str = PathCombineA(dest, "C:\\", too_long);
579     ok(str == NULL, "Expected str == NULL, got %p\n", str);
580     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
581     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
582
583     /* try a directory longer than MAX_PATH */
584     SetLastError(0xdeadbeef);
585     lstrcpyA(dest, "control");
586     str = PathCombineA(dest, too_long, "one\\two\\three");
587     ok(str == NULL, "Expected str == NULL, got %p\n", str);
588     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
589     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
590
591     memset(one, 'b', HALF_LEN);
592     memset(two, 'c', HALF_LEN);
593     one[HALF_LEN - 1] = '\0';
594     two[HALF_LEN - 1] = '\0';
595
596     /* destination string is longer than MAX_PATH, but not the constituent parts */
597     SetLastError(0xdeadbeef);
598     lstrcpyA(dest, "control");
599     str = PathCombineA(dest, one, two);
600     ok(str == NULL, "Expected str == NULL, got %p\n", str);
601     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
602     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
603 }
604
605 static void test_PathAddBackslash(void)
606 {
607     LPSTR str;
608     char path[MAX_PATH];
609     char too_long[LONG_LEN];
610
611     /* try a NULL path */
612     SetLastError(0xdeadbeef);
613     str = PathAddBackslashA(NULL);
614     ok(str == NULL, "Expected str == NULL, got %p\n", str);
615     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
616
617     /* try an empty path */
618     path[0] = '\0';
619     SetLastError(0xdeadbeef);
620     str = PathAddBackslashA(path);
621     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
622     ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
623     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
624
625     /* try a relative path */
626     lstrcpyA(path, "one\\two");
627     SetLastError(0xdeadbeef);
628     str = PathAddBackslashA(path);
629     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
630     ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
631     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
632
633     /* try periods */
634     lstrcpyA(path, "one\\..\\two");
635     SetLastError(0xdeadbeef);
636     str = PathAddBackslashA(path);
637     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
638     ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
639     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
640
641     /* try just a space */
642     lstrcpyA(path, " ");
643     SetLastError(0xdeadbeef);
644     str = PathAddBackslashA(path);
645     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
646     ok(!lstrcmp(path, " \\"), "Expected  \\, got %s\n", path);
647     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
648
649     /* path already has backslash */
650     lstrcpyA(path, "C:\\one\\");
651     SetLastError(0xdeadbeef);
652     str = PathAddBackslashA(path);
653     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
654     ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
655     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
656
657     memset(too_long, 'a', LONG_LEN);
658     too_long[LONG_LEN - 1] = '\0';
659
660     /* path is longer than MAX_PATH */
661     SetLastError(0xdeadbeef);
662     str = PathAddBackslashA(too_long);
663     ok(str == NULL, "Expected str == NULL, got %p\n", str);
664     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
665 }
666
667 static void test_PathAppendA(void)
668 {
669     char path[MAX_PATH];
670     char too_long[LONG_LEN];
671     char one[HALF_LEN], two[HALF_LEN];
672     BOOL res;
673
674     lstrcpy(path, "C:\\one");
675
676     /* try NULL pszMore */
677     SetLastError(0xdeadbeef);
678     res = PathAppendA(path, NULL);
679     ok(!res, "Expected failure\n");
680     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
681     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
682
683     /* try empty pszMore */
684     SetLastError(0xdeadbeef);
685     res = PathAppendA(path, "");
686     ok(res, "Expected success\n");
687     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
688     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
689
690     /* try NULL pszPath */
691     SetLastError(0xdeadbeef);
692     res = PathAppendA(NULL, "two\\three");
693     ok(!res, "Expected failure\n");
694     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
695
696     /* try empty pszPath */
697     path[0] = '\0';
698     SetLastError(0xdeadbeef);
699     res = PathAppendA(path, "two\\three");
700     ok(res, "Expected success\n");
701     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
702     ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
703
704     /* try empty pszPath and empty pszMore */
705     path[0] = '\0';
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, "\\"), "Expected \\, got %s\n", path);
711
712     /* try legit params */
713     lstrcpy(path, "C:\\one");
714     SetLastError(0xdeadbeef);
715     res = PathAppendA(path, "two\\three");
716     ok(res, "Expected success\n");
717     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
718     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
719
720     /* try pszPath with backslash after it */
721     lstrcpy(path, "C:\\one\\");
722     SetLastError(0xdeadbeef);
723     res = PathAppendA(path, "two\\three");
724     ok(res, "Expected success\n");
725     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
726     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
727
728     /* try pszMore with backslash before it */
729     lstrcpy(path, "C:\\one");
730     SetLastError(0xdeadbeef);
731     res = PathAppendA(path, "\\two\\three");
732     ok(res, "Expected success\n");
733     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
734     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
735
736     /* try pszMore with backslash after it */
737     lstrcpy(path, "C:\\one");
738     SetLastError(0xdeadbeef);
739     res = PathAppendA(path, "two\\three\\");
740     ok(res, "Expected success\n");
741     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
742     ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
743
744     /* try spaces in pszPath */
745     lstrcpy(path, "C: \\ one ");
746     SetLastError(0xdeadbeef);
747     res = PathAppendA(path, "two\\three");
748     ok(res, "Expected success\n");
749     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
750     ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
751
752     /* try spaces in pszMore */
753     lstrcpy(path, "C:\\one");
754     SetLastError(0xdeadbeef);
755     res = PathAppendA(path, " two \\ three ");
756     ok(res, "Expected success\n");
757     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
758     ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
759
760     /* pszPath is too long */
761     memset(too_long, 'a', LONG_LEN);
762     too_long[LONG_LEN - 1] = '\0';
763     SetLastError(0xdeadbeef);
764     res = PathAppendA(too_long, "two\\three");
765     ok(!res, "Expected failure\n");
766     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
767     ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
768
769     /* pszMore is too long */
770     lstrcpy(path, "C:\\one");
771     memset(too_long, 'a', LONG_LEN);
772     too_long[LONG_LEN - 1] = '\0';
773     SetLastError(0xdeadbeef);
774     res = PathAppendA(path, too_long);
775     ok(!res, "Expected failure\n");
776     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
777     ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path));
778
779     /* both params combined are too long */
780     memset(one, 'a', HALF_LEN);
781     one[HALF_LEN - 1] = '\0';
782     memset(two, 'b', HALF_LEN);
783     two[HALF_LEN - 1] = '\0';
784     SetLastError(0xdeadbeef);
785     res = PathAppendA(one, two);
786     ok(!res, "Expected failure\n");
787     ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one));
788     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
789 }
790
791 static void test_PathCanonicalizeA(void)
792 {
793     char dest[LONG_LEN + MAX_PATH];
794     char too_long[LONG_LEN];
795     BOOL res;
796
797     /* try a NULL source */
798     lstrcpy(dest, "test");
799     SetLastError(0xdeadbeef);
800     res = PathCanonicalizeA(dest, NULL);
801     ok(!res, "Expected failure\n");
802     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
803        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
804     ok(dest[0] == 0 || !lstrcmp(dest, "test"),
805        "Expected either an empty string (Vista) or test, got %s\n", dest);
806
807     /* try an empty source */
808     lstrcpy(dest, "test");
809     SetLastError(0xdeadbeef);
810     res = PathCanonicalizeA(dest, "");
811     ok(res, "Expected success\n");
812     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
813     ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest);
814
815     /* try a NULL dest */
816     SetLastError(0xdeadbeef);
817     res = PathCanonicalizeA(NULL, "C:\\");
818     ok(!res, "Expected failure\n");
819     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
820        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
821
822     /* try empty dest */
823     dest[0] = '\0';
824     SetLastError(0xdeadbeef);
825     res = PathCanonicalizeA(dest, "C:\\");
826     ok(res, "Expected success\n");
827     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
828     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
829
830     /* try non-empty dest */
831     lstrcpy(dest, "test");
832     SetLastError(0xdeadbeef);
833     res = PathCanonicalizeA(dest, "C:\\");
834     ok(res, "Expected success\n");
835     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
836     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
837
838     /* try a space for source */
839     lstrcpy(dest, "test");
840     SetLastError(0xdeadbeef);
841     res = PathCanonicalizeA(dest, " ");
842     ok(res, "Expected success\n");
843     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
844     ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
845
846     /* try a relative path */
847     lstrcpy(dest, "test");
848     SetLastError(0xdeadbeef);
849     res = PathCanonicalizeA(dest, "one\\two");
850     ok(res, "Expected success\n");
851     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
852     ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
853
854     /* try current dir and previous dir */
855     lstrcpy(dest, "test");
856     SetLastError(0xdeadbeef);
857     res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
858     ok(res, "Expected success\n");
859     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
860     ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
861
862     /* try simple forward slashes */
863     lstrcpy(dest, "test");
864     SetLastError(0xdeadbeef);
865     res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
866     ok(res, "Expected success\n");
867     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
868     ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
869        "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
870
871     /* try simple forward slashes with same dir */
872     lstrcpy(dest, "test");
873     SetLastError(0xdeadbeef);
874     res = PathCanonicalizeA(dest, "C:\\one/.\\two");
875     ok(res, "Expected success\n");
876     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
877     ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
878
879     /* try simple forward slashes with change dir */
880     lstrcpy(dest, "test");
881     SetLastError(0xdeadbeef);
882     res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
883     ok(res, "Expected success\n");
884     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
885     ok(!lstrcmp(dest, "C:\\one/.") ||
886        !lstrcmp(dest, "C:\\one/"), /* Vista */
887        "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest);
888
889     /* try forward slashes with change dirs
890      * NOTE: if there is a forward slash in between two backslashes,
891      * everything in between the two backslashes is considered on dir
892      */
893     lstrcpy(dest, "test");
894     SetLastError(0xdeadbeef);
895     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
896     ok(res, "Expected success\n");
897     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
898     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
899
900     /* try src is too long */
901     memset(too_long, 'a', LONG_LEN);
902     too_long[LONG_LEN - 1] = '\0';
903     lstrcpy(dest, "test");
904     SetLastError(0xdeadbeef);
905     res = PathCanonicalizeA(dest, too_long);
906     ok(!res, "Expected failure\n");
907     todo_wine
908     {
909         ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */,
910         "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
911     }
912     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
913 }
914
915 static void test_PathFindExtensionA(void)
916 {
917     LPSTR ext;
918     char path[MAX_PATH];
919     char too_long[LONG_LEN];
920
921     /* try a NULL path */
922     SetLastError(0xdeadbeef);
923     ext = PathFindExtensionA(NULL);
924     ok(ext == NULL, "Expected NULL, got %p\n", ext);
925     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
926
927     /* try an empty path */
928     path[0] = '\0';
929     SetLastError(0xdeadbeef);
930     ext = PathFindExtensionA(path);
931     ok(ext == path, "Expected ext == path, got %p\n", ext);
932     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
933     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
934
935     /* try a path without an extension */
936     lstrcpy(path, "file");
937     SetLastError(0xdeadbeef);
938     ext = PathFindExtensionA(path);
939     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
940     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
941     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
942
943     /* try a path with an extension */
944     lstrcpy(path, "file.txt");
945     SetLastError(0xdeadbeef);
946     ext = PathFindExtensionA(path);
947     ok(ext == path + lstrlen("file"),
948        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
949     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
950     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
951
952     /* try a path with two extensions */
953     lstrcpy(path, "file.txt.doc");
954     SetLastError(0xdeadbeef);
955     ext = PathFindExtensionA(path);
956     ok(ext == path + lstrlen("file.txt"),
957        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
958     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
959     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
960
961     /* try a path longer than MAX_PATH without an extension*/
962     memset(too_long, 'a', LONG_LEN);
963     too_long[LONG_LEN - 1] = '\0';
964     SetLastError(0xdeadbeef);
965     ext = PathFindExtensionA(too_long);
966     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
967     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
968
969     /* try a path longer than MAX_PATH with an extension*/
970     memset(too_long, 'a', LONG_LEN);
971     too_long[LONG_LEN - 1] = '\0';
972     lstrcpy(too_long + 300, ".abcde");
973     too_long[lstrlen(too_long)] = 'a';
974     SetLastError(0xdeadbeef);
975     ext = PathFindExtensionA(too_long);
976     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
977     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
978     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
979 }
980
981 static void test_PathBuildRootA(void)
982 {
983     LPSTR root;
984     char path[10];
985     char root_expected[26][4];
986     char drive;
987     int j;
988
989     /* set up the expected paths */
990     for (drive = 'A'; drive <= 'Z'; drive++)
991         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
992
993     /* test the expected values */
994     for (j = 0; j < 26; j++)
995     {
996         SetLastError(0xdeadbeef);
997         lstrcpy(path, "aaaaaaaaa");
998         root = PathBuildRootA(path, j);
999         ok(root == path, "Expected root == path, got %p\n", root);
1000         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1001         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1002     }
1003
1004     /* test a negative drive number */
1005     SetLastError(0xdeadbeef);
1006     lstrcpy(path, "aaaaaaaaa");
1007     root = PathBuildRootA(path, -1);
1008     ok(root == path, "Expected root == path, got %p\n", root);
1009     ok(!lstrcmp(path, "aaaaaaaaa") ||
1010        lstrlenA(path) == 0, /* Vista */
1011        "Expected aaaaaaaaa or empty string, got %s\n", path);
1012     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1013
1014     /* test a drive number greater than 25 */
1015     SetLastError(0xdeadbeef);
1016     lstrcpy(path, "aaaaaaaaa");
1017     root = PathBuildRootA(path, 26);
1018     ok(root == path, "Expected root == path, got %p\n", root);
1019     ok(!lstrcmp(path, "aaaaaaaaa") ||
1020        lstrlenA(path) == 0, /* Vista */
1021        "Expected aaaaaaaaa or empty string, 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 }