user32/tests: Add more A and W test combinations for dde.
[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[LONG_LEN + 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/.") ||
895        !lstrcmp(dest, "C:\\one/"), /* Vista */
896        "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest);
897
898     /* try forward slashes with change dirs
899      * NOTE: if there is a forward slash in between two backslashes,
900      * everything in between the two backslashes is considered on dir
901      */
902     lstrcpy(dest, "test");
903     SetLastError(0xdeadbeef);
904     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
905     ok(res, "Expected success\n");
906     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
907     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
908
909     /* try src is too long */
910     memset(too_long, 'a', LONG_LEN);
911     too_long[LONG_LEN - 1] = '\0';
912     lstrcpy(dest, "test");
913     SetLastError(0xdeadbeef);
914     res = PathCanonicalizeA(dest, too_long);
915     ok(!res, "Expected failure\n");
916     todo_wine
917     {
918         ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */,
919         "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
920     }
921     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
922 }
923
924 static void test_PathFindExtensionA(void)
925 {
926     LPSTR ext;
927     char path[MAX_PATH];
928     char too_long[LONG_LEN];
929
930     /* try a NULL path */
931     SetLastError(0xdeadbeef);
932     ext = PathFindExtensionA(NULL);
933     ok(ext == NULL, "Expected NULL, got %p\n", ext);
934     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
935
936     /* try an empty path */
937     path[0] = '\0';
938     SetLastError(0xdeadbeef);
939     ext = PathFindExtensionA(path);
940     ok(ext == path, "Expected ext == path, got %p\n", ext);
941     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
942     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
943
944     /* try a path without an extension */
945     lstrcpy(path, "file");
946     SetLastError(0xdeadbeef);
947     ext = PathFindExtensionA(path);
948     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
949     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
950     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
951
952     /* try a path with an extension */
953     lstrcpy(path, "file.txt");
954     SetLastError(0xdeadbeef);
955     ext = PathFindExtensionA(path);
956     ok(ext == path + lstrlen("file"),
957        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
958     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
959     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
960
961     /* try a path with two extensions */
962     lstrcpy(path, "file.txt.doc");
963     SetLastError(0xdeadbeef);
964     ext = PathFindExtensionA(path);
965     ok(ext == path + lstrlen("file.txt"),
966        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
967     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
968     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
969
970     /* try a path longer than MAX_PATH without an extension*/
971     memset(too_long, 'a', LONG_LEN);
972     too_long[LONG_LEN - 1] = '\0';
973     SetLastError(0xdeadbeef);
974     ext = PathFindExtensionA(too_long);
975     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
976     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
977
978     /* try a path longer than MAX_PATH with an extension*/
979     memset(too_long, 'a', LONG_LEN);
980     too_long[LONG_LEN - 1] = '\0';
981     lstrcpy(too_long + 300, ".abcde");
982     too_long[lstrlen(too_long)] = 'a';
983     SetLastError(0xdeadbeef);
984     ext = PathFindExtensionA(too_long);
985     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
986     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
987     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
988 }
989
990 static void test_PathBuildRootA(void)
991 {
992     LPSTR root;
993     char path[10];
994     char root_expected[26][4];
995     char drive;
996     int j;
997
998     /* set up the expected paths */
999     for (drive = 'A'; drive <= 'Z'; drive++)
1000         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1001
1002     /* test the expected values */
1003     for (j = 0; j < 26; j++)
1004     {
1005         SetLastError(0xdeadbeef);
1006         lstrcpy(path, "aaaaaaaaa");
1007         root = PathBuildRootA(path, j);
1008         ok(root == path, "Expected root == path, got %p\n", root);
1009         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1010         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1011     }
1012
1013     /* test a negative drive number */
1014     SetLastError(0xdeadbeef);
1015     lstrcpy(path, "aaaaaaaaa");
1016     root = PathBuildRootA(path, -1);
1017     ok(root == path, "Expected root == path, got %p\n", root);
1018     ok(!lstrcmp(path, "aaaaaaaaa") ||
1019        lstrlenA(path) == 0, /* Vista */
1020        "Expected aaaaaaaaa or empty string, got %s\n", path);
1021     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1022
1023     /* test a drive number greater than 25 */
1024     SetLastError(0xdeadbeef);
1025     lstrcpy(path, "aaaaaaaaa");
1026     root = PathBuildRootA(path, 26);
1027     ok(root == path, "Expected root == path, got %p\n", root);
1028     ok(!lstrcmp(path, "aaaaaaaaa") ||
1029        lstrlenA(path) == 0, /* Vista */
1030        "Expected aaaaaaaaa or empty string, got %s\n", path);
1031     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1032
1033     /* length of path is less than 4 */
1034     SetLastError(0xdeadbeef);
1035     lstrcpy(path, "aa");
1036     root = PathBuildRootA(path, 0);
1037     ok(root == path, "Expected root == path, got %p\n", root);
1038     ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1039     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1040
1041     /* path is NULL */
1042     SetLastError(0xdeadbeef);
1043     root = PathBuildRootA(NULL, 0);
1044     ok(root == NULL, "Expected root == NULL, got %p\n", root);
1045     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1046 }
1047
1048 static void test_PathCommonPrefixA(void)
1049 {
1050     char path1[MAX_PATH], path2[MAX_PATH];
1051     char out[MAX_PATH];
1052     int count;
1053
1054     /* test NULL path1 */
1055     SetLastError(0xdeadbeef);
1056     lstrcpy(path2, "C:\\");
1057     lstrcpy(out, "aaa");
1058     count = PathCommonPrefixA(NULL, path2, out);
1059     ok(count == 0, "Expected 0, got %i\n", count);
1060     todo_wine
1061     {
1062         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1063     }
1064     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1065     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1066
1067     /* test NULL path2 */
1068     SetLastError(0xdeadbeef);
1069     lstrcpy(path1, "C:\\");
1070     lstrcpy(out, "aaa");
1071     count = PathCommonPrefixA(path1, NULL, out);
1072     ok(count == 0, "Expected 0, got %i\n", count);
1073     todo_wine
1074     {
1075         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1076     }
1077     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1078     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1079
1080     /* test empty path1 */
1081     SetLastError(0xdeadbeef);
1082     path1[0] = '\0';
1083     lstrcpy(path2, "C:\\");
1084     lstrcpy(out, "aaa");
1085     count = PathCommonPrefixA(path1, path2, out);
1086     ok(count == 0, "Expected 0, got %i\n", count);
1087     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1088     ok(lstrlen(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1089     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1090     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1091
1092     /* test empty path1 */
1093     SetLastError(0xdeadbeef);
1094     path2[0] = '\0';
1095     lstrcpy(path1, "C:\\");
1096     lstrcpy(out, "aaa");
1097     count = PathCommonPrefixA(path1, path2, out);
1098     ok(count == 0, "Expected 0, got %i\n", count);
1099     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1100     ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1101     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1102     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1103
1104     /* paths are legit, out is NULL */
1105     SetLastError(0xdeadbeef);
1106     lstrcpy(path1, "C:\\");
1107     lstrcpy(path2, "C:\\");
1108     count = PathCommonPrefixA(path1, path2, NULL);
1109     ok(count == 3, "Expected 3, got %i\n", count);
1110     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1111     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1112     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1113
1114     /* all parameters legit */
1115     SetLastError(0xdeadbeef);
1116     lstrcpy(path1, "C:\\");
1117     lstrcpy(path2, "C:\\");
1118     lstrcpy(out, "aaa");
1119     count = PathCommonPrefixA(path1, path2, out);
1120     ok(count == 3, "Expected 3, got %i\n", count);
1121     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1122     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1123     ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1124     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1125
1126     /* path1 and path2 not the same, but common prefix */
1127     SetLastError(0xdeadbeef);
1128     lstrcpy(path1, "C:\\one\\two");
1129     lstrcpy(path2, "C:\\one\\three");
1130     lstrcpy(out, "aaa");
1131     count = PathCommonPrefixA(path1, path2, out);
1132     ok(count == 6, "Expected 6, got %i\n", count);
1133     ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1134     ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1135     ok(!lstrcmp(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1136     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1137
1138     /* try . prefix */
1139     SetLastError(0xdeadbeef);
1140     lstrcpy(path1, "one\\.two");
1141     lstrcpy(path2, "one\\.three");
1142     lstrcpy(out, "aaa");
1143     count = PathCommonPrefixA(path1, path2, out);
1144     ok(count == 3, "Expected 3, got %i\n", count);
1145     ok(!lstrcmp(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1146     ok(!lstrcmp(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1147     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1148     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1149
1150     /* try .. prefix */
1151     SetLastError(0xdeadbeef);
1152     lstrcpy(path1, "one\\..two");
1153     lstrcpy(path2, "one\\..three");
1154     lstrcpy(out, "aaa");
1155     count = PathCommonPrefixA(path1, path2, out);
1156     ok(count == 3, "Expected 3, got %i\n", count);
1157     ok(!lstrcmp(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1158     ok(!lstrcmp(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1159     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1160     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1161
1162     /* try ... prefix */
1163     SetLastError(0xdeadbeef);
1164     lstrcpy(path1, "one\\...two");
1165     lstrcpy(path2, "one\\...three");
1166     lstrcpy(out, "aaa");
1167     count = PathCommonPrefixA(path1, path2, out);
1168     ok(count == 3, "Expected 3, got %i\n", count);
1169     ok(!lstrcmp(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1170     ok(!lstrcmp(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1171     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1172     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1173
1174     /* try .\ prefix */
1175     SetLastError(0xdeadbeef);
1176     lstrcpy(path1, "one\\.\\two");
1177     lstrcpy(path2, "one\\.\\three");
1178     lstrcpy(out, "aaa");
1179     count = PathCommonPrefixA(path1, path2, out);
1180     ok(count == 5, "Expected 5, got %i\n", count);
1181     ok(!lstrcmp(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1182     ok(!lstrcmp(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1183     ok(!lstrcmp(out, "one\\."), "Expected one\\., got %s\n", out);
1184     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1185
1186     /* try ..\ prefix */
1187     SetLastError(0xdeadbeef);
1188     lstrcpy(path1, "one\\..\\two");
1189     lstrcpy(path2, "one\\..\\three");
1190     lstrcpy(out, "aaa");
1191     count = PathCommonPrefixA(path1, path2, out);
1192     ok(count == 6, "Expected 6, got %i\n", count);
1193     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1194     ok(!lstrcmp(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1195     ok(!lstrcmp(out, "one\\.."), "Expected one\\.., got %s\n", out);
1196     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1197
1198     /* try ...\\ prefix */
1199     SetLastError(0xdeadbeef);
1200     lstrcpy(path1, "one\\...\\two");
1201     lstrcpy(path2, "one\\...\\three");
1202     lstrcpy(out, "aaa");
1203     count = PathCommonPrefixA(path1, path2, out);
1204     ok(count == 7, "Expected 7, got %i\n", count);
1205     ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1206     ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1207     ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1208     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1209
1210     /* try prefix that is not an msdn labeled prefix type */
1211     SetLastError(0xdeadbeef);
1212     lstrcpy(path1, "same");
1213     lstrcpy(path2, "same");
1214     lstrcpy(out, "aaa");
1215     count = PathCommonPrefixA(path1, path2, out);
1216     ok(count == 4, "Expected 4, got %i\n", count);
1217     ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1218     ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1219     ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1220     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1221
1222     /* try . after directory */
1223     SetLastError(0xdeadbeef);
1224     lstrcpy(path1, "one\\mid.\\two");
1225     lstrcpy(path2, "one\\mid.\\three");
1226     lstrcpy(out, "aaa");
1227     count = PathCommonPrefixA(path1, path2, out);
1228     ok(count == 8, "Expected 8, got %i\n", count);
1229     ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1230     ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1231     ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1232     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1233
1234     /* try . in the middle of a directory */
1235     SetLastError(0xdeadbeef);
1236     lstrcpy(path1, "one\\mid.end\\two");
1237     lstrcpy(path2, "one\\mid.end\\three");
1238     lstrcpy(out, "aaa");
1239     count = PathCommonPrefixA(path1, path2, out);
1240     ok(count == 11, "Expected 11, got %i\n", count);
1241     ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1242     ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1243     ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1244     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1245
1246     /* try comparing a .. with the expanded path */
1247     SetLastError(0xdeadbeef);
1248     lstrcpy(path1, "one\\..\\two");
1249     lstrcpy(path2, "two");
1250     lstrcpy(out, "aaa");
1251     count = PathCommonPrefixA(path1, path2, out);
1252     ok(count == 0, "Expected 0, got %i\n", count);
1253     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1254     ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1255     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1256     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1257 }
1258
1259 static void test_PathUnquoteSpaces(void)
1260 {
1261     int i;
1262     for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1263     {
1264         char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1265         WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1266         WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1267
1268         PathUnquoteSpacesA(path);
1269         ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1270            TEST_PATH_UNQUOTE_SPACES[i].path, path,
1271            TEST_PATH_UNQUOTE_SPACES[i].result);
1272
1273         PathUnquoteSpacesW(pathW);
1274         ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1275            TEST_PATH_UNQUOTE_SPACES[i].path);
1276         FreeWideString(pathW);
1277         FreeWideString(resultW);
1278         HeapFree(GetProcessHeap(), 0, path);
1279     }
1280 }
1281
1282 /* ################ */
1283
1284 START_TEST(path)
1285 {
1286   hShlwapi = GetModuleHandleA("shlwapi.dll");
1287
1288   test_PathSearchAndQualify();
1289   test_PathCreateFromUrl();
1290   test_PathIsUrl();
1291
1292   test_PathAddBackslash();
1293   test_PathMakePretty();
1294   test_PathMatchSpec();
1295
1296   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1297    * ordinal number in some native versions. Check this to prevent a crash.
1298    */
1299   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1300   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1301   {
1302     test_PathIsValidCharA();
1303
1304      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1305      if (pPathIsValidCharW) test_PathIsValidCharW();
1306   }
1307
1308   pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1309   if (pPathCombineW)
1310     test_PathCombineW();
1311
1312   test_PathCombineA();
1313   test_PathAppendA();
1314   test_PathCanonicalizeA();
1315   test_PathFindExtensionA();
1316   test_PathBuildRootA();
1317   test_PathCommonPrefixA();
1318   test_PathUnquoteSpaces();
1319 }