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