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