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