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