mshtml: Added put_backgroundImage implementation.
[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(str == dest, "Expected str == dest, got %p\n", str);
541     ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
542     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
543
544     /* try forward slashes */
545     SetLastError(0xdeadbeef);
546     lstrcpyA(dest, "control");
547     str = PathCombineA(dest, "C:\\", "one/two/three\\");
548     ok(str == dest, "Expected str == dest, got %p\n", str);
549     ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
550     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
551
552     /* try a really weird directory */
553     SetLastError(0xdeadbeef);
554     lstrcpyA(dest, "control");
555     str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
556     ok(str == dest, "Expected str == dest, got %p\n", str);
557     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
558     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
559
560     /* try periods */
561     SetLastError(0xdeadbeef);
562     lstrcpyA(dest, "control");
563     str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
564     ok(str == dest, "Expected str == dest, got %p\n", str);
565     ok(!lstrcmp(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
566     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
567
568     /* try .. as file */
569     /* try forward slashes */
570     SetLastError(0xdeadbeef);
571     lstrcpyA(dest, "control");
572     str = PathCombineA(dest, "C:\\", "..");
573     ok(str == dest, "Expected str == dest, got %p\n", str);
574     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
575     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
576
577     memset(too_long, 'a', LONG_LEN);
578     too_long[LONG_LEN - 1] = '\0';
579
580     /* try a file longer than MAX_PATH */
581     SetLastError(0xdeadbeef);
582     lstrcpyA(dest, "control");
583     str = PathCombineA(dest, "C:\\", too_long);
584     ok(str == NULL, "Expected str == NULL, got %p\n", str);
585     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
586     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
587
588     /* try a directory longer than MAX_PATH */
589     SetLastError(0xdeadbeef);
590     lstrcpyA(dest, "control");
591     str = PathCombineA(dest, too_long, "one\\two\\three");
592     ok(str == NULL, "Expected str == NULL, got %p\n", str);
593     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
594     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
595
596     memset(one, 'b', HALF_LEN);
597     memset(two, 'c', HALF_LEN);
598     one[HALF_LEN - 1] = '\0';
599     two[HALF_LEN - 1] = '\0';
600
601     /* destination string is longer than MAX_PATH, but not the constituent parts */
602     SetLastError(0xdeadbeef);
603     lstrcpyA(dest, "control");
604     str = PathCombineA(dest, one, two);
605     ok(str == NULL, "Expected str == NULL, got %p\n", str);
606     ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
607     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
608 }
609
610 static void test_PathAddBackslash(void)
611 {
612     LPSTR str;
613     char path[MAX_PATH];
614     char too_long[LONG_LEN];
615
616     /* try a NULL path */
617     SetLastError(0xdeadbeef);
618     str = PathAddBackslashA(NULL);
619     ok(str == NULL, "Expected str == NULL, got %p\n", str);
620     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
621
622     /* try an empty path */
623     path[0] = '\0';
624     SetLastError(0xdeadbeef);
625     str = PathAddBackslashA(path);
626     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
627     ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
628     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
629
630     /* try a relative path */
631     lstrcpyA(path, "one\\two");
632     SetLastError(0xdeadbeef);
633     str = PathAddBackslashA(path);
634     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
635     ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
636     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
637
638     /* try periods */
639     lstrcpyA(path, "one\\..\\two");
640     SetLastError(0xdeadbeef);
641     str = PathAddBackslashA(path);
642     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
643     ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
644     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
645
646     /* try just a space */
647     lstrcpyA(path, " ");
648     SetLastError(0xdeadbeef);
649     str = PathAddBackslashA(path);
650     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
651     ok(!lstrcmp(path, " \\"), "Expected  \\, got %s\n", path);
652     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
653
654     /* path already has backslash */
655     lstrcpyA(path, "C:\\one\\");
656     SetLastError(0xdeadbeef);
657     str = PathAddBackslashA(path);
658     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
659     ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
660     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
661
662     memset(too_long, 'a', LONG_LEN);
663     too_long[LONG_LEN - 1] = '\0';
664
665     /* path is longer than MAX_PATH */
666     SetLastError(0xdeadbeef);
667     str = PathAddBackslashA(too_long);
668     ok(str == NULL, "Expected str == NULL, got %p\n", str);
669     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
670 }
671
672 static void test_PathAppendA(void)
673 {
674     char path[MAX_PATH];
675     char too_long[LONG_LEN];
676     char one[HALF_LEN], two[HALF_LEN];
677     BOOL res;
678
679     lstrcpy(path, "C:\\one");
680
681     /* try NULL pszMore */
682     SetLastError(0xdeadbeef);
683     res = PathAppendA(path, NULL);
684     ok(!res, "Expected failure\n");
685     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
686     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
687
688     /* try empty pszMore */
689     SetLastError(0xdeadbeef);
690     res = PathAppendA(path, "");
691     ok(res, "Expected success\n");
692     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
693     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
694
695     /* try NULL pszPath */
696     SetLastError(0xdeadbeef);
697     res = PathAppendA(NULL, "two\\three");
698     ok(!res, "Expected failure\n");
699     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
700
701     /* try empty pszPath */
702     path[0] = '\0';
703     SetLastError(0xdeadbeef);
704     res = PathAppendA(path, "two\\three");
705     ok(res, "Expected success\n");
706     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
707     ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
708
709     /* try empty pszPath and empty pszMore */
710     path[0] = '\0';
711     SetLastError(0xdeadbeef);
712     res = PathAppendA(path, "");
713     ok(res, "Expected success\n");
714     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
715     ok(!lstrcmp(path, "\\"), "Expected \\, got %s\n", path);
716
717     /* try legit params */
718     lstrcpy(path, "C:\\one");
719     SetLastError(0xdeadbeef);
720     res = PathAppendA(path, "two\\three");
721     ok(res, "Expected success\n");
722     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
723     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
724
725     /* try pszPath with backslash after it */
726     lstrcpy(path, "C:\\one\\");
727     SetLastError(0xdeadbeef);
728     res = PathAppendA(path, "two\\three");
729     ok(res, "Expected success\n");
730     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
731     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
732
733     /* try pszMore with backslash before it */
734     lstrcpy(path, "C:\\one");
735     SetLastError(0xdeadbeef);
736     res = PathAppendA(path, "\\two\\three");
737     ok(res, "Expected success\n");
738     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
739     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
740
741     /* try pszMore with backslash after it */
742     lstrcpy(path, "C:\\one");
743     SetLastError(0xdeadbeef);
744     res = PathAppendA(path, "two\\three\\");
745     ok(res, "Expected success\n");
746     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
747     ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
748
749     /* try spaces in pszPath */
750     lstrcpy(path, "C: \\ one ");
751     SetLastError(0xdeadbeef);
752     res = PathAppendA(path, "two\\three");
753     ok(res, "Expected success\n");
754     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
755     ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
756
757     /* try spaces in pszMore */
758     lstrcpy(path, "C:\\one");
759     SetLastError(0xdeadbeef);
760     res = PathAppendA(path, " two \\ three ");
761     ok(res, "Expected success\n");
762     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
763     ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
764
765     /* pszPath is too long */
766     memset(too_long, 'a', LONG_LEN);
767     too_long[LONG_LEN - 1] = '\0';
768     SetLastError(0xdeadbeef);
769     res = PathAppendA(too_long, "two\\three");
770     ok(!res, "Expected failure\n");
771     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
772     ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
773
774     /* pszMore is too long */
775     lstrcpy(path, "C:\\one");
776     memset(too_long, 'a', LONG_LEN);
777     too_long[LONG_LEN - 1] = '\0';
778     SetLastError(0xdeadbeef);
779     res = PathAppendA(path, too_long);
780     ok(!res, "Expected failure\n");
781     todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
782     ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path));
783
784     /* both params combined are too long */
785     memset(one, 'a', HALF_LEN);
786     one[HALF_LEN - 1] = '\0';
787     memset(two, 'b', HALF_LEN);
788     two[HALF_LEN - 1] = '\0';
789     SetLastError(0xdeadbeef);
790     res = PathAppendA(one, two);
791     ok(!res, "Expected failure\n");
792     ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one));
793     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
794 }
795
796 static void test_PathCanonicalizeA(void)
797 {
798     char dest[MAX_PATH];
799     char too_long[LONG_LEN];
800     BOOL res;
801
802     /* try a NULL source */
803     lstrcpy(dest, "test");
804     SetLastError(0xdeadbeef);
805     res = PathCanonicalizeA(dest, NULL);
806     ok(!res, "Expected failure\n");
807     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
808        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
809     todo_wine
810     {
811         ok(!lstrcmp(dest, "test"), "Expected test, got %s\n", dest);
812     }
813
814     /* try an empty source */
815     lstrcpy(dest, "test");
816     SetLastError(0xdeadbeef);
817     res = PathCanonicalizeA(dest, "");
818     ok(res, "Expected success\n");
819     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
820     ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest);
821
822     /* try a NULL dest */
823     SetLastError(0xdeadbeef);
824     res = PathCanonicalizeA(NULL, "C:\\");
825     ok(!res, "Expected failure\n");
826     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
827        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
828
829     /* try empty dest */
830     dest[0] = '\0';
831     SetLastError(0xdeadbeef);
832     res = PathCanonicalizeA(dest, "C:\\");
833     ok(res, "Expected success\n");
834     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
835     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
836
837     /* try non-empty dest */
838     lstrcpy(dest, "test");
839     SetLastError(0xdeadbeef);
840     res = PathCanonicalizeA(dest, "C:\\");
841     ok(res, "Expected success\n");
842     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
843     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
844
845     /* try a space for source */
846     lstrcpy(dest, "test");
847     SetLastError(0xdeadbeef);
848     res = PathCanonicalizeA(dest, " ");
849     ok(res, "Expected success\n");
850     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
851     ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
852
853     /* try a relative path */
854     lstrcpy(dest, "test");
855     SetLastError(0xdeadbeef);
856     res = PathCanonicalizeA(dest, "one\\two");
857     ok(res, "Expected success\n");
858     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
859     ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
860
861     /* try current dir and previous dir */
862     lstrcpy(dest, "test");
863     SetLastError(0xdeadbeef);
864     res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
865     ok(res, "Expected success\n");
866     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
867     ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
868
869     /* try simple forward slashes */
870     lstrcpy(dest, "test");
871     SetLastError(0xdeadbeef);
872     res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
873     ok(res, "Expected success\n");
874     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
875     ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
876        "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
877
878     /* try simple forward slashes with same dir */
879     lstrcpy(dest, "test");
880     SetLastError(0xdeadbeef);
881     res = PathCanonicalizeA(dest, "C:\\one/.\\two");
882     ok(res, "Expected success\n");
883     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
884     ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
885
886     /* try simple forward slashes with change dir */
887     lstrcpy(dest, "test");
888     SetLastError(0xdeadbeef);
889     res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
890     ok(res, "Expected success\n");
891     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
892     ok(!lstrcmp(dest, "C:\\one/."), "Expected C:\\one/., got %s\n", dest);
893
894     /* try forward slashes with change dirs
895      * NOTE: if there is a forward slash in between two backslashes,
896      * everything in between the two backslashes is considered on dir
897      */
898     lstrcpy(dest, "test");
899     SetLastError(0xdeadbeef);
900     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
901     ok(res, "Expected success\n");
902     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
903     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
904
905     /* try src is too long */
906     memset(too_long, 'a', LONG_LEN);
907     too_long[LONG_LEN - 1] = '\0';
908     lstrcpy(dest, "test");
909     SetLastError(0xdeadbeef);
910     res = PathCanonicalizeA(dest, too_long);
911     ok(!res, "Expected failure\n");
912     todo_wine
913     {
914         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
915     }
916     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
917 }
918
919 static void test_PathFindExtensionA(void)
920 {
921     LPSTR ext;
922     char path[MAX_PATH];
923     char too_long[LONG_LEN];
924
925     /* try a NULL path */
926     SetLastError(0xdeadbeef);
927     ext = PathFindExtensionA(NULL);
928     ok(ext == NULL, "Expected NULL, got %p\n", ext);
929     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
930
931     /* try an empty path */
932     path[0] = '\0';
933     SetLastError(0xdeadbeef);
934     ext = PathFindExtensionA(path);
935     ok(ext == path, "Expected ext == path, got %p\n", ext);
936     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
937     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
938
939     /* try a path without an extension */
940     lstrcpy(path, "file");
941     SetLastError(0xdeadbeef);
942     ext = PathFindExtensionA(path);
943     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
944     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
945     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
946
947     /* try a path with an extension */
948     lstrcpy(path, "file.txt");
949     SetLastError(0xdeadbeef);
950     ext = PathFindExtensionA(path);
951     ok(ext == path + lstrlen("file"),
952        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
953     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
954     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
955
956     /* try a path with two extensions */
957     lstrcpy(path, "file.txt.doc");
958     SetLastError(0xdeadbeef);
959     ext = PathFindExtensionA(path);
960     ok(ext == path + lstrlen("file.txt"),
961        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
962     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
963     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
964
965     /* try a path longer than MAX_PATH without an extension*/
966     memset(too_long, 'a', LONG_LEN);
967     too_long[LONG_LEN - 1] = '\0';
968     SetLastError(0xdeadbeef);
969     ext = PathFindExtensionA(too_long);
970     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
971     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
972
973     /* try a path longer than MAX_PATH with an extension*/
974     memset(too_long, 'a', LONG_LEN);
975     too_long[LONG_LEN - 1] = '\0';
976     lstrcpy(too_long + 300, ".abcde");
977     too_long[lstrlen(too_long)] = 'a';
978     SetLastError(0xdeadbeef);
979     ext = PathFindExtensionA(too_long);
980     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
981     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
982     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
983 }
984
985 static void test_PathBuildRootA(void)
986 {
987     LPSTR root;
988     char path[10];
989     char root_expected[26][4];
990     char drive;
991     int j;
992
993     /* set up the expected paths */
994     for (drive = 'A'; drive <= 'Z'; drive++)
995         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
996
997     /* test the expected values */
998     for (j = 0; j < 26; j++)
999     {
1000         SetLastError(0xdeadbeef);
1001         lstrcpy(path, "aaaaaaaaa");
1002         root = PathBuildRootA(path, j);
1003         ok(root == path, "Expected root == path, got %p\n", root);
1004         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1005         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1006     }
1007
1008     /* test a negative drive number */
1009     SetLastError(0xdeadbeef);
1010     lstrcpy(path, "aaaaaaaaa");
1011     root = PathBuildRootA(path, -1);
1012     ok(root == path, "Expected root == path, got %p\n", root);
1013     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1014     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1015
1016     /* test a drive number greater than 25 */
1017     SetLastError(0xdeadbeef);
1018     lstrcpy(path, "aaaaaaaaa");
1019     root = PathBuildRootA(path, 26);
1020     ok(root == path, "Expected root == path, got %p\n", root);
1021     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1022     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1023
1024     /* length of path is less than 4 */
1025     SetLastError(0xdeadbeef);
1026     lstrcpy(path, "aa");
1027     root = PathBuildRootA(path, 0);
1028     ok(root == path, "Expected root == path, got %p\n", root);
1029     ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1030     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1031
1032     /* path is NULL */
1033     SetLastError(0xdeadbeef);
1034     root = PathBuildRootA(NULL, 0);
1035     ok(root == NULL, "Expected root == NULL, got %p\n", root);
1036     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1037 }
1038
1039 static void test_PathCommonPrefixA(void)
1040 {
1041     char path1[MAX_PATH], path2[MAX_PATH];
1042     char out[MAX_PATH];
1043     int count;
1044
1045     /* test NULL path1 */
1046     SetLastError(0xdeadbeef);
1047     lstrcpy(path2, "C:\\");
1048     lstrcpy(out, "aaa");
1049     count = PathCommonPrefixA(NULL, path2, out);
1050     ok(count == 0, "Expected 0, got %i\n", count);
1051     todo_wine
1052     {
1053         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1054     }
1055     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1056     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1057
1058     /* test NULL path2 */
1059     SetLastError(0xdeadbeef);
1060     lstrcpy(path1, "C:\\");
1061     lstrcpy(out, "aaa");
1062     count = PathCommonPrefixA(path1, NULL, out);
1063     ok(count == 0, "Expected 0, got %i\n", count);
1064     todo_wine
1065     {
1066         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1067     }
1068     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1069     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1070
1071     /* test empty path1 */
1072     SetLastError(0xdeadbeef);
1073     path1[0] = '\0';
1074     lstrcpy(path2, "C:\\");
1075     lstrcpy(out, "aaa");
1076     count = PathCommonPrefixA(path1, path2, out);
1077     ok(count == 0, "Expected 0, got %i\n", count);
1078     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1079     ok(lstrlen(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1080     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1081     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1082
1083     /* test empty path1 */
1084     SetLastError(0xdeadbeef);
1085     path2[0] = '\0';
1086     lstrcpy(path1, "C:\\");
1087     lstrcpy(out, "aaa");
1088     count = PathCommonPrefixA(path1, path2, out);
1089     ok(count == 0, "Expected 0, got %i\n", count);
1090     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1091     ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1092     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1093     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1094
1095     /* paths are legit, out is NULL */
1096     SetLastError(0xdeadbeef);
1097     lstrcpy(path1, "C:\\");
1098     lstrcpy(path2, "C:\\");
1099     count = PathCommonPrefixA(path1, path2, NULL);
1100     ok(count == 3, "Expected 3, got %i\n", count);
1101     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1102     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1103     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1104
1105     /* all parameters legit */
1106     SetLastError(0xdeadbeef);
1107     lstrcpy(path1, "C:\\");
1108     lstrcpy(path2, "C:\\");
1109     lstrcpy(out, "aaa");
1110     count = PathCommonPrefixA(path1, path2, out);
1111     ok(count == 3, "Expected 3, got %i\n", count);
1112     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1113     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1114     ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1115     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1116
1117     /* path1 and path2 not the same, but common prefix */
1118     SetLastError(0xdeadbeef);
1119     lstrcpy(path1, "C:\\one\\two");
1120     lstrcpy(path2, "C:\\one\\three");
1121     lstrcpy(out, "aaa");
1122     count = PathCommonPrefixA(path1, path2, out);
1123     ok(count == 6, "Expected 6, got %i\n", count);
1124     ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1125     ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1126     ok(!lstrcmp(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1127     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1128
1129     /* try . prefix */
1130     SetLastError(0xdeadbeef);
1131     lstrcpy(path1, "one\\.two");
1132     lstrcpy(path2, "one\\.three");
1133     lstrcpy(out, "aaa");
1134     count = PathCommonPrefixA(path1, path2, out);
1135     ok(count == 3, "Expected 3, got %i\n", count);
1136     ok(!lstrcmp(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1137     ok(!lstrcmp(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1138     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1139     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1140
1141     /* try .. prefix */
1142     SetLastError(0xdeadbeef);
1143     lstrcpy(path1, "one\\..two");
1144     lstrcpy(path2, "one\\..three");
1145     lstrcpy(out, "aaa");
1146     count = PathCommonPrefixA(path1, path2, out);
1147     ok(count == 3, "Expected 3, got %i\n", count);
1148     ok(!lstrcmp(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1149     ok(!lstrcmp(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1150     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1151     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1152
1153     /* try ... prefix */
1154     SetLastError(0xdeadbeef);
1155     lstrcpy(path1, "one\\...two");
1156     lstrcpy(path2, "one\\...three");
1157     lstrcpy(out, "aaa");
1158     count = PathCommonPrefixA(path1, path2, out);
1159     ok(count == 3, "Expected 3, got %i\n", count);
1160     ok(!lstrcmp(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1161     ok(!lstrcmp(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1162     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1163     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1164
1165     /* try .\ prefix */
1166     SetLastError(0xdeadbeef);
1167     lstrcpy(path1, "one\\.\\two");
1168     lstrcpy(path2, "one\\.\\three");
1169     lstrcpy(out, "aaa");
1170     count = PathCommonPrefixA(path1, path2, out);
1171     ok(count == 5, "Expected 5, got %i\n", count);
1172     ok(!lstrcmp(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1173     ok(!lstrcmp(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1174     ok(!lstrcmp(out, "one\\."), "Expected one\\., got %s\n", out);
1175     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1176
1177     /* try ..\ prefix */
1178     SetLastError(0xdeadbeef);
1179     lstrcpy(path1, "one\\..\\two");
1180     lstrcpy(path2, "one\\..\\three");
1181     lstrcpy(out, "aaa");
1182     count = PathCommonPrefixA(path1, path2, out);
1183     ok(count == 6, "Expected 6, got %i\n", count);
1184     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1185     ok(!lstrcmp(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1186     ok(!lstrcmp(out, "one\\.."), "Expected one\\.., got %s\n", out);
1187     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1188
1189     /* try ...\\ prefix */
1190     SetLastError(0xdeadbeef);
1191     lstrcpy(path1, "one\\...\\two");
1192     lstrcpy(path2, "one\\...\\three");
1193     lstrcpy(out, "aaa");
1194     count = PathCommonPrefixA(path1, path2, out);
1195     ok(count == 7, "Expected 7, got %i\n", count);
1196     ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1197     ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1198     ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1199     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1200
1201     /* try prefix that is not an msdn labeled prefix type */
1202     SetLastError(0xdeadbeef);
1203     lstrcpy(path1, "same");
1204     lstrcpy(path2, "same");
1205     lstrcpy(out, "aaa");
1206     count = PathCommonPrefixA(path1, path2, out);
1207     ok(count == 4, "Expected 4, got %i\n", count);
1208     ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1209     ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1210     ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1211     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1212
1213     /* try . after directory */
1214     SetLastError(0xdeadbeef);
1215     lstrcpy(path1, "one\\mid.\\two");
1216     lstrcpy(path2, "one\\mid.\\three");
1217     lstrcpy(out, "aaa");
1218     count = PathCommonPrefixA(path1, path2, out);
1219     ok(count == 8, "Expected 8, got %i\n", count);
1220     ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1221     ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1222     ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1223     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1224
1225     /* try . in the middle of a directory */
1226     SetLastError(0xdeadbeef);
1227     lstrcpy(path1, "one\\mid.end\\two");
1228     lstrcpy(path2, "one\\mid.end\\three");
1229     lstrcpy(out, "aaa");
1230     count = PathCommonPrefixA(path1, path2, out);
1231     ok(count == 11, "Expected 11, got %i\n", count);
1232     ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1233     ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1234     ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1235     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1236
1237     /* try comparing a .. with the expanded path */
1238     SetLastError(0xdeadbeef);
1239     lstrcpy(path1, "one\\..\\two");
1240     lstrcpy(path2, "two");
1241     lstrcpy(out, "aaa");
1242     count = PathCommonPrefixA(path1, path2, out);
1243     ok(count == 0, "Expected 0, got %i\n", count);
1244     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1245     ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1246     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1247     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1248 }
1249
1250 static void test_PathUnquoteSpaces(void)
1251 {
1252     int i;
1253     for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1254     {
1255         char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1256         WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1257         WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1258
1259         PathUnquoteSpacesA(path);
1260         ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1261            TEST_PATH_UNQUOTE_SPACES[i].path, path,
1262            TEST_PATH_UNQUOTE_SPACES[i].result);
1263
1264         PathUnquoteSpacesW(pathW);
1265         ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1266            TEST_PATH_UNQUOTE_SPACES[i].path);
1267         FreeWideString(pathW);
1268         FreeWideString(resultW);
1269         HeapFree(GetProcessHeap(), 0, path);
1270     }
1271 }
1272
1273 /* ################ */
1274
1275 START_TEST(path)
1276 {
1277   hShlwapi = GetModuleHandleA("shlwapi.dll");
1278
1279   test_PathSearchAndQualify();
1280   test_PathCreateFromUrl();
1281   test_PathIsUrl();
1282
1283   test_PathAddBackslash();
1284   test_PathMakePretty();
1285   test_PathMatchSpec();
1286
1287   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1288    * ordinal number in some native versions. Check this to prevent a crash.
1289    */
1290   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1291   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1292   {
1293     test_PathIsValidCharA();
1294
1295      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1296      if (pPathIsValidCharW) test_PathIsValidCharW();
1297   }
1298
1299   pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1300   if (pPathCombineW)
1301     test_PathCombineW();
1302
1303   test_PathCombineA();
1304   test_PathAppendA();
1305   test_PathCanonicalizeA();
1306   test_PathFindExtensionA();
1307   test_PathBuildRootA();
1308   test_PathCommonPrefixA();
1309   test_PathUnquoteSpaces();
1310 }