janitorial: Remove remaining NULL checks before free() (found by Smatch).
[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 const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
37 const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
38 const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
39
40 typedef struct _TEST_URL_CANONICALIZE {
41     const char *url;
42     DWORD flags;
43     HRESULT expectret;
44     const char *expecturl;
45 } TEST_URL_CANONICALIZE;
46
47 const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
48     /*FIXME {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/"},*/
49     {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests"},
50     {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
51     {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
52     {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests"},
53     {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests"},
54     {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/"},
55     {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/"},
56     {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/"},
57     {"http://www.winehq.org/tests/..", 0, S_OK, "http://www.winehq.org/"},
58     {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/"},
59     {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"},
60     {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"},
61     {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example"},
62     {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example"},
63     {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example"},
64     {"http://www.winehq.org/tests/..\\#example", 0, S_OK, "http://www.winehq.org/#example"},
65     {"http://www.winehq.org\\tests/../#example", 0, S_OK, "http://www.winehq.org/#example"},
66     {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example"},
67     {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar"},
68     {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar"},
69     {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"},
70     {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"},
71     {"file:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
72     {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
73     {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
74     {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
75     {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar"},
76     {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar"},
77     {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar"},
78     {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about"},
79     {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about"},
80     {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file"},
81     {"file:///c:\\dir\\file", 0, S_OK, "file:///c:/dir/file"},
82     {"c:dir\\file", 0, S_OK, "file:///c:dir/file"},
83     {"A", 0, S_OK, "A"},
84     {"", 0, S_OK, ""}
85 };
86
87 typedef struct _TEST_URL_ESCAPE {
88     const char *url;
89     DWORD flags;
90     DWORD expectescaped;
91     HRESULT expectret;
92     const char *expecturl;
93 } TEST_URL_ESCAPE;
94
95 const TEST_URL_ESCAPE TEST_ESCAPE[] = {
96     {"http://www.winehq.org/tests0", 0, 0, S_OK, "http://www.winehq.org/tests0"},
97     {"http://www.winehq.org/tests1\n", 0, 0, S_OK, "http://www.winehq.org/tests1%0A"},
98     {"http://www.winehq.org/tests2\r", 0, 0, S_OK, "http://www.winehq.org/tests2%0D"},
99     {"http://www.winehq.org/tests3\r", URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, 0, S_OK, "http://www.winehq.org/tests3\r"},
100     {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
101     {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
102     {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
103
104     {"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
105     {"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
106     {"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
107     {"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
108     {"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
109     {"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
110     {"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
111     {"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
112     {"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
113     {"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"},
114     {"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
115     {"file:\\\\foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
116     {"file:\\\\\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
117     {"file:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
118     {"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"},
119     {"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"},
120     {"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, 0, S_OK, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"},
121     {"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"},
122     {"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"},
123
124     {"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"},
125     {"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"},
126     {"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"},
127     {"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"},
128     {"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"},
129     {"/foo/%5C", 0, 0, S_OK, "/foo/%5C"},
130     {"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"},
131
132     {"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"},
133     {"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"},
134     {"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
135     {"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
136     {"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"},
137     {"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
138     {"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
139     {"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"},
140     {"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"},
141     {"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
142     {"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
143     {"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
144     {"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
145     {"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"},
146     {"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"},
147     {"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"},
148
149     {"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"},
150     {"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
151     {"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
152
153     {"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"},
154     {"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"},
155     {"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"},
156     {"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"},
157     {"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"},
158     {"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"},
159     {"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"},
160     {"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"},
161     {"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"},
162
163     {"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
164     {"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
165     {"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, 0, S_OK, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"},
166
167     {"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
168     {"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"},
169     {"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"},
170     {"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"},
171     {"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"},
172     {"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"},
173     {"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"}
174 };
175
176 typedef struct _TEST_URL_COMBINE {
177     const char *url1;
178     const char *url2;
179     DWORD flags;
180     HRESULT expectret;
181     const char *expecturl;
182 } TEST_URL_COMBINE;
183
184 const TEST_URL_COMBINE TEST_COMBINE[] = {
185     {"http://www.winehq.org/tests", "tests1", 0, S_OK, "http://www.winehq.org/tests1"},
186     {"http://www.%77inehq.org/tests", "tests1", 0, S_OK, "http://www.%77inehq.org/tests1"},
187     /*FIXME {"http://www.winehq.org/tests", "../tests2", 0, S_OK, "http://www.winehq.org/tests2"},*/
188     {"http://www.winehq.org/tests/", "../tests3", 0, S_OK, "http://www.winehq.org/tests3"},
189     {"http://www.winehq.org/tests/test1", "test2", 0, S_OK, "http://www.winehq.org/tests/test2"},
190     {"http://www.winehq.org/tests/../tests", "tests4", 0, S_OK, "http://www.winehq.org/tests4"},
191     {"http://www.winehq.org/tests/../tests/", "tests5", 0, S_OK, "http://www.winehq.org/tests/tests5"},
192     {"http://www.winehq.org/tests/../tests/", "/tests6/..", 0, S_OK, "http://www.winehq.org/"},
193     {"http://www.winehq.org/tests/../tests/..", "tests7/..", 0, S_OK, "http://www.winehq.org/"},
194     {"http://www.winehq.org/tests/?query=x&return=y", "tests8", 0, S_OK, "http://www.winehq.org/tests/tests8"},
195     {"http://www.winehq.org/tests/#example", "tests9", 0, S_OK, "http://www.winehq.org/tests/tests9"},
196     {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."},
197     {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"},
198     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}
199 };
200
201 struct {
202     const char *path;
203     const char *url;
204     DWORD ret;
205 } TEST_URLFROMPATH [] = {
206     {"foo", "file:foo", S_OK},
207     {"foo\\bar", "file:foo/bar", S_OK},
208     {"\\foo\\bar", "file:///foo/bar", S_OK},
209     {"c:\\foo\\bar", "file:///c:/foo/bar", S_OK},
210     {"c:foo\\bar", "file:///c:foo/bar", S_OK},
211     {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK},
212     {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK},
213 #if 0
214     /* The following test fails on native shlwapi as distributed with Win95/98.
215      * Wine matches the behaviour of later versions.
216      */
217     {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE}
218 #endif
219 };
220
221 struct {
222     const char *url;
223     const char *path;
224     DWORD ret;
225 } TEST_PATHFROMURL[] = {
226     {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK},
227     {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK},
228     {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK},
229     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
230     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
231     {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK},
232     {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK},
233     {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK},
234     {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK},
235     {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK},
236     {"file://c:/foo/bar", "c:\\foo\\bar", S_OK},
237     {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK},
238     {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK},
239     {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK},
240     {"file:/foo/bar", "\\foo\\bar", S_OK},
241     {"file:/foo/bar/", "\\foo\\bar\\", S_OK},
242     {"file:foo/bar", "foo\\bar", S_OK},
243     {"file:c:/foo/bar", "c:\\foo\\bar", S_OK},
244     {"file:c|/foo/bar", "c:\\foo\\bar", S_OK},
245     {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK},
246     {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK},
247 /*    {"file:////c:/foo/foo%20bar", "c:\\foo\\foo%20bar", S_OK},*/
248
249     {"c:\\foo\\bar", NULL, E_INVALIDARG},
250     {"foo/bar", NULL, E_INVALIDARG},
251     {"http://foo/bar", NULL, E_INVALIDARG},
252
253 };
254
255 struct {
256     char url[30];
257     const char *expect;
258 } TEST_URL_UNESCAPE[] = {
259     {"file://foo/bar", "file://foo/bar"},
260     {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"}
261 };
262
263
264 struct {
265     const char *path;
266     BOOL expect;
267 } TEST_PATH_IS_URL[] = {
268     {"http://foo/bar", TRUE},
269     {"c:\\foo\\bar", FALSE},
270     {"foo://foo/bar", TRUE},
271     {"foo\\bar", FALSE},
272     {"foo.bar", FALSE},
273     {"bogusscheme:", TRUE},
274     {"http:partial", TRUE}
275 };
276
277 struct {
278     const char *url;
279     BOOL expectOpaque;
280     BOOL expectFile;
281 } TEST_URLIS_ATTRIBS[] = {
282     {   "ftp:",                                         FALSE,  FALSE   },
283     {   "http:",                                        FALSE,  FALSE   },
284     {   "gopher:",                                      FALSE,  FALSE   },
285     {   "mailto:",                                      TRUE,   FALSE   },
286     {   "news:",                                        FALSE,  FALSE   },
287     {   "nntp:",                                        FALSE,  FALSE   },
288     {   "telnet:",                                      FALSE,  FALSE   },
289     {   "wais:",                                        FALSE,  FALSE   },
290     {   "file:",                                        FALSE,  TRUE    },
291     {   "mk:",                                          FALSE,  FALSE   },
292     {   "https:",                                       FALSE,  FALSE   },
293     {   "shell:",                                       TRUE,   FALSE   },
294     {   "https:",                                       FALSE,  FALSE   },
295     {   "snews:",                                       FALSE,  FALSE   },
296     {   "local:",                                       FALSE,  FALSE   },
297     {   "javascript:",                                  TRUE,   FALSE   },
298     {   "vbscript:",                                    TRUE,   FALSE   },
299     {   "about:",                                       TRUE,   FALSE   },
300     {   "res:",                                         FALSE,  FALSE   },
301     {   "bogusscheme:",                                 FALSE,  FALSE   },
302     {   "file:\\\\e:\\b\\c",                            FALSE,  TRUE    },
303     {   "file://e:/b/c",                                FALSE,  TRUE    },
304     {   "http:partial",                                 FALSE,  FALSE   },
305     {   "mailto://www.winehq.org/test.html",            TRUE,   FALSE   },
306     {   "file:partial",                                 FALSE,  TRUE    }
307 };
308
309 struct {
310     const char *path;
311     const char *result;
312 } TEST_PATH_UNQUOTE_SPACES[] = {
313     { "abcdef",                    "abcdef"         },
314     { "\"abcdef\"",                "abcdef"         },
315     { "\"abcdef",                  "\"abcdef"       },
316     { "abcdef\"",                  "abcdef\""       },
317     { "\"\"abcdef\"\"",            "\"abcdef\""     },
318     { "abc\"def",                  "abc\"def"       },
319     { "\"abc\"def",                "\"abc\"def"     },
320     { "\"abc\"def\"",              "abc\"def"       },
321     { "\'abcdef\'",                "\'abcdef\'"     },
322     { "\"\"",                      ""               },
323     { "\"",                        ""               }
324 };
325
326 static LPWSTR GetWideString(const char* szString)
327 {
328   LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
329   
330   MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
331
332   return wszString;
333 }
334
335 static void FreeWideString(LPWSTR wszString)
336 {
337    HeapFree(GetProcessHeap(), 0, wszString);
338 }
339
340 static LPSTR strdupA(LPCSTR p)
341 {
342     LPSTR ret;
343     DWORD len = (strlen(p) + 1);
344     ret = HeapAlloc(GetProcessHeap(), 0, len);
345     memcpy(ret, p, len);
346     return ret;
347 }
348
349 static void hash_url(const char* szUrl)
350 {
351   LPCSTR szTestUrl = szUrl;
352   LPWSTR wszTestUrl = GetWideString(szTestUrl);
353   
354   DWORD cbSize = sizeof(DWORD);
355   DWORD dwHash1, dwHash2;
356   ok(UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize) == S_OK, "UrlHashA didn't return S_OK\n");
357   ok(UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize) == S_OK, "UrlHashW didn't return S_OK\n");
358
359   FreeWideString(wszTestUrl);
360
361   ok(dwHash1 == dwHash2, "Hashes didn't compare\n");
362 }
363
364 static void test_UrlHash(void)
365 {
366   hash_url(TEST_URL_1);
367   hash_url(TEST_URL_2);
368   hash_url(TEST_URL_3);
369 }
370
371 static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const char* szExpected)
372 {
373   CHAR szPart[INTERNET_MAX_URL_LENGTH];
374   WCHAR wszPart[INTERNET_MAX_URL_LENGTH];
375   LPWSTR wszUrl = GetWideString(szUrl);
376   LPWSTR wszConvertedPart;
377
378   DWORD dwSize;
379
380   dwSize = INTERNET_MAX_URL_LENGTH;
381   ok( UrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartA for \"%s\" part 0x%08x didn't return S_OK but \"%s\"\n", szUrl, dwPart, szPart);
382   dwSize = INTERNET_MAX_URL_LENGTH;
383   ok( UrlGetPartW(wszUrl, wszPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartW didn't return S_OK\n" );
384
385   wszConvertedPart = GetWideString(szPart);
386
387   ok(lstrcmpW(wszPart,wszConvertedPart)==0, "Strings didn't match between ascii and unicode UrlGetPart!\n");
388
389   FreeWideString(wszUrl);
390   FreeWideString(wszConvertedPart);
391
392   /* Note that v6.0 and later don't return '?' with the query */
393   ok(strcmp(szPart,szExpected)==0 ||
394      (*szExpected=='?' && !strcmp(szPart,szExpected+1)),
395          "Expected %s, but got %s\n", szExpected, szPart);
396 }
397
398 static void test_UrlGetPart(void)
399 {
400   CHAR szPart[INTERNET_MAX_URL_LENGTH];
401   DWORD dwSize;
402   HRESULT res;
403
404   dwSize = sizeof szPart;
405   szPart[0]='x'; szPart[1]=0;
406   res = UrlGetPartA("hi", szPart, &dwSize, URL_PART_SCHEME, 0);
407   todo_wine {
408   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08X\n", res);
409   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
410   }
411   dwSize = sizeof szPart;
412   szPart[0]='x'; szPart[1]=0;
413   res = UrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0);
414   todo_wine {
415   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08X\n", res);
416   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
417   }
418   
419   test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost");
420   test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21");
421   test_url_part(TEST_URL_3, URL_PART_USERNAME, 0, "foo");
422   test_url_part(TEST_URL_3, URL_PART_PASSWORD, 0, "bar");
423   test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http");
424   test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y");
425 }
426
427 static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
428 {
429     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
430     DWORD dwEscaped;
431     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
432     WCHAR *urlW, *expected_urlW;
433     dwEscaped=INTERNET_MAX_URL_LENGTH;
434
435     ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08x from \"%s\"\n", dwExpectReturn, szUrl);
436     ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
437     
438     dwEscaped = INTERNET_MAX_URL_LENGTH;
439     urlW = GetWideString(szUrl);
440     expected_urlW = GetWideString(szExpectUrl);
441     ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08x from \"%s\"\n", dwExpectReturn, szUrl);
442     WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
443     ok(lstrcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08x\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
444     FreeWideString(urlW);
445     FreeWideString(expected_urlW);
446
447 }
448
449 static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
450 {
451     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
452     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
453     LPWSTR wszUrl = GetWideString(szUrl);
454     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
455     LPWSTR wszConvertedUrl;
456     
457     DWORD dwSize;
458     
459     dwSize = INTERNET_MAX_URL_LENGTH;
460     ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
461     ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08x\n", dwExpectReturn);
462     ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08x Expected \"%s\", but got \"%s\"\n", dwFlags, szExpectUrl, szReturnUrl);
463
464     dwSize = INTERNET_MAX_URL_LENGTH;
465     ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
466     ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08x\n", dwExpectReturn);
467     wszConvertedUrl = GetWideString(szReturnUrl);
468     ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n");
469     FreeWideString(wszConvertedUrl);
470     
471             
472     FreeWideString(wszUrl);
473     FreeWideString(wszExpectUrl);
474 }
475
476
477 static void test_UrlEscape(void)
478 {
479     unsigned int i;
480     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
481         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
482                               TEST_ESCAPE[i].expectret, TEST_ESCAPE[i].expecturl);
483     }
484 }
485
486 static void test_UrlCanonicalize(void)
487 {
488     unsigned int i;
489     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
490     DWORD dwSize;
491     HRESULT hr;
492
493     for(i=0; i<sizeof(TEST_CANONICALIZE)/sizeof(TEST_CANONICALIZE[0]); i++) {
494         test_url_canonicalize(TEST_CANONICALIZE[i].url, TEST_CANONICALIZE[i].flags,
495                               TEST_CANONICALIZE[i].expectret, TEST_CANONICALIZE[i].expecturl);
496     }
497
498     /* move to TEST_CANONICALIZE when fixed */
499     dwSize = sizeof szReturnUrl;
500     ok(UrlCanonicalizeA("c:\\tests\\foo bar", szReturnUrl, &dwSize, 0) == S_OK, "UrlCanonicalizeA didn't return 0x%08x\n", S_OK);
501     todo_wine {
502         ok(strcmp(szReturnUrl,"file:///c:/tests/foo%20bar")==0, "UrlCanonicalizeA got %s\n", szReturnUrl);
503     }
504
505     dwSize = sizeof szReturnUrl;
506     /*LimeWire online installer calls this*/
507     hr = UrlCanonicalizeA("/uri-res/N2R?urn:sha1:B3K", szReturnUrl, &dwSize,URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/);
508     ok(hr==S_OK,"UrlCanonicalizeA returned 0x%08x instead of S_OK\n", hr);
509     todo_wine {
510         ok(strcmp(szReturnUrl,"/uri-res/N2R?urn:sha1:B3K")==0, "UrlCanonicalizeA got \"%s\"  instead of \"/uri-res/N2R?urn:sha1:B3K\"\n", szReturnUrl);
511     }
512 }
513
514 static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
515 {
516     HRESULT hr;
517     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
518     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
519     LPWSTR wszUrl1 = GetWideString(szUrl1);
520     LPWSTR wszUrl2 = GetWideString(szUrl2);
521     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
522     LPWSTR wszConvertedUrl;
523
524     DWORD dwSize;
525     DWORD dwExpectLen = lstrlen(szExpectUrl);
526
527     hr = UrlCombineA(szUrl1, szUrl2, NULL, NULL, dwFlags);
528     ok(hr == E_INVALIDARG, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, E_INVALIDARG);
529     
530     dwSize = 0;
531     hr = UrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags);
532     ok(hr == E_POINTER, "Checking length of string, return was 0x%08x, expected 0x%08x\n", hr, E_POINTER);
533     ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1);
534
535     dwSize--;
536     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
537     ok(hr == E_POINTER, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, E_POINTER);
538     ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1);
539     
540     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
541     ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, dwExpectReturn);
542     ok(dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen);
543     if(SUCCEEDED(hr)) {
544         ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
545     }
546
547     dwSize = 0;
548     hr = UrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags);
549     ok(hr == E_POINTER, "Checking length of string, return was 0x%08x, expected 0x%08x\n", hr, E_POINTER);
550     ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1);
551
552     dwSize--;
553     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
554     ok(hr == E_POINTER, "UrlCombineA returned 0x%08x, expected 0x%08x\n", hr, E_POINTER);
555     ok(dwSize == dwExpectLen+1, "Got length %d, expected %d\n", dwSize, dwExpectLen+1);
556     
557     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
558     ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08x, expected 0x%08x\n", hr, dwExpectReturn);
559     ok(dwSize == dwExpectLen, "Got length %d, expected %d\n", dwSize, dwExpectLen);
560     if(SUCCEEDED(hr)) {
561         wszConvertedUrl = GetWideString(szReturnUrl);
562         ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n");
563         FreeWideString(wszConvertedUrl);
564     }
565
566     FreeWideString(wszUrl1);
567     FreeWideString(wszUrl2);
568     FreeWideString(wszExpectUrl);
569 }
570
571 static void test_UrlCombine(void)
572 {
573     unsigned int i;
574     for(i=0; i<sizeof(TEST_COMBINE)/sizeof(TEST_COMBINE[0]); i++) {
575         test_url_combine(TEST_COMBINE[i].url1, TEST_COMBINE[i].url2, TEST_COMBINE[i].flags,
576                          TEST_COMBINE[i].expectret, TEST_COMBINE[i].expecturl);
577     }
578 }
579
580 static void test_UrlCreateFromPath(void)
581 {
582     size_t i;
583     char ret_url[INTERNET_MAX_URL_LENGTH];
584     DWORD len, ret;
585     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
586     WCHAR *pathW, *urlW;
587
588     for(i = 0; i < sizeof(TEST_URLFROMPATH) / sizeof(TEST_URLFROMPATH[0]); i++) {
589         len = INTERNET_MAX_URL_LENGTH;
590         ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
591         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08x from path %s\n", ret, TEST_URLFROMPATH[i].path);
592         ok(!lstrcmpi(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
593         ok(len == strlen(ret_url), "ret len %d from path %s\n", len, TEST_URLFROMPATH[i].path);
594
595         len = INTERNET_MAX_URL_LENGTH;
596         pathW = GetWideString(TEST_URLFROMPATH[i].path);
597         urlW = GetWideString(TEST_URLFROMPATH[i].url);
598         ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
599         WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
600         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08x from path L\"%s\", expected %08x\n",
601            ret, TEST_URLFROMPATH[i].path, TEST_URLFROMPATH[i].ret);
602         ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n", ret_url, TEST_URLFROMPATH[i].url, TEST_URLFROMPATH[i].path);
603         ok(len == lstrlenW(ret_urlW), "ret len %d from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
604         FreeWideString(urlW);
605         FreeWideString(pathW);
606     }
607 }
608
609 static void test_UrlIs(void)
610 {
611     BOOL ret;
612     size_t i;
613     WCHAR wurl[80];
614
615     for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
616         MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80);
617
618         ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL );
619         ok( ret == TEST_PATH_IS_URL[i].expect,
620             "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
621             TEST_PATH_IS_URL[i].expect );
622
623         ret = UrlIsW( wurl, URLIS_URL );
624         ok( ret == TEST_PATH_IS_URL[i].expect,
625             "returned %d from path (UrlIsW) %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
626             TEST_PATH_IS_URL[i].expect );
627     }
628     for(i = 0; i < sizeof(TEST_URLIS_ATTRIBS) / sizeof(TEST_URLIS_ATTRIBS[0]); i++) {
629         MultiByteToWideChar(CP_ACP, 0, TEST_URLIS_ATTRIBS[i].url, -1, wurl, 80);
630
631         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_OPAQUE);
632         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
633             "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
634             TEST_URLIS_ATTRIBS[i].expectOpaque );
635         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_FILEURL);
636         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
637             "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
638             TEST_URLIS_ATTRIBS[i].expectFile );
639
640         ret = UrlIsW( wurl, URLIS_OPAQUE);
641         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
642             "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
643             TEST_URLIS_ATTRIBS[i].expectOpaque );
644         ret = UrlIsW( wurl, URLIS_FILEURL);
645         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
646             "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
647             TEST_URLIS_ATTRIBS[i].expectFile );
648     }
649 }
650
651 static void test_UrlUnescape(void)
652 {
653     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
654     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
655     WCHAR *urlW, *expected_urlW; 
656     DWORD dwEscaped;
657     size_t i;
658     static char inplace[] = "file:///C:/Program%20Files";
659     static WCHAR inplaceW[] = {'f','i','l','e',':','/','/','/','C',':','/',
660                                'P','r','o','g','r','a','m','%','2','0','F','i','l','e','s',0};
661
662     for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) { 
663         dwEscaped=INTERNET_MAX_URL_LENGTH;
664         ok(UrlUnescapeA(TEST_URL_UNESCAPE[i].url, szReturnUrl, &dwEscaped, 0) == S_OK, "UrlEscapeA didn't return 0x%08x from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
665         ok(strcmp(szReturnUrl,TEST_URL_UNESCAPE[i].expect)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", TEST_URL_UNESCAPE[i].expect, szReturnUrl, TEST_URL_UNESCAPE[i].url);
666
667         dwEscaped = INTERNET_MAX_URL_LENGTH;
668         urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
669         expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
670         ok(UrlUnescapeW(urlW, ret_urlW, &dwEscaped, 0) == S_OK, "UrlEscapeW didn't return 0x%08x from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
671         WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
672         ok(lstrcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", TEST_URL_UNESCAPE[i].expect, szReturnUrl, TEST_URL_UNESCAPE[i].url, 0L);
673         FreeWideString(urlW);
674         FreeWideString(expected_urlW);
675     }
676
677     dwEscaped = sizeof(inplace);
678     ok(UrlUnescapeA(inplace, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeA failed unexpectedly\n");
679
680     dwEscaped = sizeof(inplaceW);
681     ok(UrlUnescapeW(inplaceW, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeW failed unexpectedly\n");
682 }
683
684 static void test_PathSearchAndQualify(void)
685 {
686     WCHAR path1[] = {'c',':','\\','f','o','o',0};
687     WCHAR expect1[] = {'c',':','\\','f','o','o',0};
688     WCHAR path2[] = {'c',':','f','o','o',0};
689     WCHAR c_drive[] = {'c',':',0}; 
690     WCHAR foo[] = {'f','o','o',0}; 
691     WCHAR path3[] = {'\\','f','o','o',0};
692     WCHAR winini[] = {'w','i','n','.','i','n','i',0};
693     WCHAR out[MAX_PATH];
694     WCHAR cur_dir[MAX_PATH];
695     WCHAR dot[] = {'.',0};
696
697     /* c:\foo */
698     ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
699        "PathSearchAndQualify rets 0\n");
700     ok(!lstrcmpiW(out, expect1), "strings don't match\n");
701
702     /* c:foo */
703     ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
704        "PathSearchAndQualify rets 0\n");
705     GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
706     PathAddBackslashW(cur_dir);
707     lstrcatW(cur_dir, foo);
708     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
709
710     /* foo */
711     ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
712        "PathSearchAndQualify rets 0\n");
713     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
714     PathAddBackslashW(cur_dir);
715     lstrcatW(cur_dir, foo);
716     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
717
718     /* \foo */
719     ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
720        "PathSearchAndQualify rets 0\n");
721     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
722     lstrcpyW(cur_dir + 2, path3);
723     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
724
725     /* win.ini */
726     ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
727        "PathSearchAndQualify rets 0\n");
728     if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
729         GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
730     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
731
732 }
733
734 static void test_PathCreateFromUrl(void)
735 {
736     size_t i;
737     char ret_path[INTERNET_MAX_URL_LENGTH];
738     DWORD len, ret;
739     WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
740     WCHAR *pathW, *urlW;
741     static const char url[] = "http://www.winehq.org";
742
743     /* Check ret_path = NULL */
744     len = sizeof(url);
745     ret = PathCreateFromUrlA(url, NULL, &len, 0); 
746     ok ( ret == E_INVALIDARG, "got 0x%08x expected E_INVALIDARG\n", ret);
747
748     for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
749         len = INTERNET_MAX_URL_LENGTH;
750         ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
751         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url);
752         if(TEST_PATHFROMURL[i].path) {
753            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);
754            ok(len == strlen(ret_path), "ret len %d from url %s\n", len, TEST_PATHFROMURL[i].url);
755         }
756         len = INTERNET_MAX_URL_LENGTH;
757         pathW = GetWideString(TEST_PATHFROMURL[i].path);
758         urlW = GetWideString(TEST_PATHFROMURL[i].url);
759         ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
760         WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
761         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
762         if(TEST_PATHFROMURL[i].path) {
763             ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
764             ok(len == lstrlenW(ret_pathW), "ret len %d from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
765         }
766         FreeWideString(urlW);
767         FreeWideString(pathW);
768     }
769 }
770
771
772 static void test_PathIsUrl(void)
773 {
774     size_t i;
775     BOOL ret;
776
777     for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
778         ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
779         ok(ret == TEST_PATH_IS_URL[i].expect,
780            "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
781            TEST_PATH_IS_URL[i].expect);
782     }
783 }
784
785 static const DWORD SHELL_charclass[] =
786 {
787     0x00000000, 0x00000000, 0x00000000, 0x00000000,
788     0x00000000, 0x00000000, 0x00000000, 0x00000000,
789     0x00000000, 0x00000000, 0x00000000, 0x00000000,
790     0x00000000, 0x00000000, 0x00000000, 0x00000000,
791     0x00000000, 0x00000000, 0x00000000, 0x00000000,
792     0x00000000, 0x00000000, 0x00000000, 0x00000000,
793     0x00000000, 0x00000000, 0x00000000, 0x00000000,
794     0x00000000, 0x00000000, 0x00000000, 0x00000000,
795     0x00000080, 0x00000100, 0x00000200, 0x00000100,
796     0x00000100, 0x00000100, 0x00000100, 0x00000100,
797     0x00000100, 0x00000100, 0x00000002, 0x00000100,
798     0x00000040, 0x00000100, 0x00000004, 0x00000000,
799     0x00000100, 0x00000100, 0x00000100, 0x00000100,
800     0x00000100, 0x00000100, 0x00000100, 0x00000100,
801     0x00000100, 0x00000100, 0x00000010, 0x00000020,
802     0x00000000, 0x00000100, 0x00000000, 0x00000001,
803     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
804     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
805     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
806     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
807     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
808     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
809     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
810     0x00000008, 0x00000100, 0x00000100, 0x00000100,
811     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
812     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
813     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
814     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
815     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
816     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
817     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
818     0x00000000, 0x00000100, 0x00000100
819 };
820
821 static void test_PathIsValidCharA(void)
822 {
823     BOOL ret;
824     unsigned int c;
825
826     ret = pPathIsValidCharA( 0x7f, 0 );
827     ok ( !ret, "PathIsValidCharA succeeded: 0x%08x\n", (DWORD)ret );
828
829     ret = pPathIsValidCharA( 0x7f, 1 );
830     ok ( !ret, "PathIsValidCharA succeeded: 0x%08x\n", (DWORD)ret );
831
832     for (c = 0; c < 0x7f; c++)
833     {
834         ret = pPathIsValidCharA( c, ~0U );
835         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
836              "PathIsValidCharA failed: 0x%02x got 0x%08x expected 0x%08x\n",
837              c, (DWORD)ret, SHELL_charclass[c] );
838     }
839
840     for (c = 0x7f; c <= 0xff; c++)
841     {
842         ret = pPathIsValidCharA( c, ~0U );
843         ok ( ret == 0x00000100,
844              "PathIsValidCharA failed: 0x%02x got 0x%08x expected 0x00000100\n",
845              c, (DWORD)ret );
846     }
847 }
848
849 static void test_PathIsValidCharW(void)
850 {
851     BOOL ret;
852     unsigned int c, err_count = 0;
853
854     ret = pPathIsValidCharW( 0x7f, 0 );
855     ok ( !ret, "PathIsValidCharW succeeded: 0x%08x\n", (DWORD)ret );
856
857     ret = pPathIsValidCharW( 0x7f, 1 );
858     ok ( !ret, "PathIsValidCharW succeeded: 0x%08x\n", (DWORD)ret );
859
860     for (c = 0; c < 0x7f; c++)
861     {
862         ret = pPathIsValidCharW( c, ~0U );
863         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
864              "PathIsValidCharW failed: 0x%02x got 0x%08x expected 0x%08x\n",
865              c, (DWORD)ret, SHELL_charclass[c] );
866     }
867
868     for (c = 0x007f; c <= 0xffff; c++)
869     {
870         ret = pPathIsValidCharW( c, ~0U );
871         ok ( ret == 0x00000100,
872              "PathIsValidCharW failed: 0x%02x got 0x%08x expected 0x00000100\n",
873              c, (DWORD)ret );
874         if (ret != 0x00000100)
875         {
876             if(++err_count > 100 ) {
877                 trace("skipping rest of PathIsValidCharW tests "
878                       "because of the current number of errors\n");
879                 break;
880             }
881         }
882     }
883 }
884
885 static void test_PathMakePretty(void)
886 {
887    char buff[MAX_PATH];
888
889    ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
890    buff[0] = '\0';
891    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
892
893    strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
894    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
895    ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
896        "PathMakePretty: Long UC name not changed\n");
897
898    strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
899    ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
900    ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
901        "PathMakePretty: Failed but modified path\n");
902
903    strcpy(buff, "TEST");
904    ok (PathMakePrettyA(buff) == TRUE,  "PathMakePretty: Short name failed\n");
905    ok (strcmp(buff, "Test") == 0,  "PathMakePretty: 1st char lowercased %s\n", buff);
906 }
907
908 static void test_PathMatchSpec(void)
909 {
910     static const char file[] = "c:\\foo\\bar\\filename.ext";
911     static const char spec1[] = ".ext";
912     static const char spec2[] = "*.ext";
913     static const char spec3[] = "*.ext ";
914     static const char spec4[] = "  *.ext";
915     static const char spec5[] = "* .ext";
916     static const char spec6[] = "*. ext";
917     static const char spec7[] = "* . ext";
918     static const char spec8[] = "*.e?t";
919     static const char spec9[] = "filename.ext";
920     static const char spec10[] = "*bar\\filename.ext";
921     static const char spec11[] = " foo; *.ext";
922     static const char spec12[] = "*.ext;*.bar";
923     static const char spec13[] = "*bar*";
924
925     ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
926     ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
927     ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
928     ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
929     todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
930     todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
931     ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
932     ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
933     ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
934     ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
935     ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
936     ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
937     ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
938 }
939
940 static void test_PathCombineW(void)
941 {
942     LPWSTR wszString, wszString2;
943    
944     wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
945
946     /* NULL test */
947     wszString = pPathCombineW(NULL, NULL, NULL);
948     ok (wszString == NULL, "Expected a NULL return\n");
949
950     /* Some NULL */
951     wszString = pPathCombineW(wszString2, NULL, NULL);
952     ok (wszString == NULL, "Expected a NULL return\n");
953  
954     HeapFree(GetProcessHeap(), 0, wszString2);
955 }
956
957 #define LONG_LEN (MAX_PATH * 2)
958 #define HALF_LEN (MAX_PATH / 2 + 1)
959
960 static void test_PathCombineA(void)
961 {
962     LPSTR str;
963     char dest[MAX_PATH];
964     char too_long[LONG_LEN];
965     char one[HALF_LEN], two[HALF_LEN];
966
967     /* try NULL dest */
968     SetLastError(0xdeadbeef);
969     str = PathCombineA(NULL, "C:\\", "one\\two\\three");
970     ok(str == NULL, "Expected NULL, got %p\n", str);
971     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
972
973     /* try NULL dest and NULL directory */
974     SetLastError(0xdeadbeef);
975     str = PathCombineA(NULL, NULL, "one\\two\\three");
976     ok(str == NULL, "Expected NULL, got %p\n", str);
977     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
978
979     /* try all NULL*/
980     SetLastError(0xdeadbeef);
981     str = PathCombineA(NULL, NULL, NULL);
982     ok(str == NULL, "Expected NULL, got %p\n", str);
983     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
984
985     /* try NULL file part */
986     SetLastError(0xdeadbeef);
987     lstrcpyA(dest, "control");
988     str = PathCombineA(dest, "C:\\", NULL);
989     ok(str == dest, "Expected str == dest, got %p\n", str);
990     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
991     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
992
993     /* try empty file part */
994     SetLastError(0xdeadbeef);
995     lstrcpyA(dest, "control");
996     str = PathCombineA(dest, "C:\\", "");
997     ok(str == dest, "Expected str == dest, got %p\n", str);
998     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
999     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1000
1001     /* try empty directory and file part */
1002     SetLastError(0xdeadbeef);
1003     lstrcpyA(dest, "control");
1004     str = PathCombineA(dest, "", "");
1005     ok(str == dest, "Expected str == dest, got %p\n", str);
1006     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
1007     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1008
1009     /* try NULL directory */
1010     SetLastError(0xdeadbeef);
1011     lstrcpyA(dest, "control");
1012     str = PathCombineA(dest, NULL, "one\\two\\three");
1013     ok(str == dest, "Expected str == dest, got %p\n", str);
1014     ok(!lstrcmp(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
1015     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1016
1017     /* try NULL directory and empty file part */
1018     SetLastError(0xdeadbeef);
1019     lstrcpyA(dest, "control");
1020     str = PathCombineA(dest, NULL, "");
1021     ok(str == dest, "Expected str == dest, got %p\n", str);
1022     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
1023     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1024
1025     /* try NULL directory and file part */
1026     SetLastError(0xdeadbeef);
1027     lstrcpyA(dest, "control");
1028     str = PathCombineA(dest, NULL, NULL);
1029     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1030     todo_wine
1031     {
1032         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1033     }
1034     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1035
1036     /* try directory without backslash */
1037     SetLastError(0xdeadbeef);
1038     lstrcpyA(dest, "control");
1039     str = PathCombineA(dest, "C:", "one\\two\\three");
1040     ok(str == dest, "Expected str == dest, got %p\n", str);
1041     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1042     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1043
1044     /* try directory with backslash */
1045     SetLastError(0xdeadbeef);
1046     lstrcpyA(dest, "control");
1047     str = PathCombineA(dest, "C:\\", "one\\two\\three");
1048     ok(str == dest, "Expected str == dest, got %p\n", str);
1049     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1050     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1051
1052     /* try directory with backslash and file with prepended backslash */
1053     SetLastError(0xdeadbeef);
1054     lstrcpyA(dest, "control");
1055     str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
1056     ok(str == dest, "Expected str == dest, got %p\n", str);
1057     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1058     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1059
1060     /* try previous test, with backslash appended as well */
1061     SetLastError(0xdeadbeef);
1062     lstrcpyA(dest, "control");
1063     str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
1064     ok(str == dest, "Expected str == dest, got %p\n", str);
1065     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1066     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1067
1068     /* try a relative directory */
1069     SetLastError(0xdeadbeef);
1070     lstrcpyA(dest, "control");
1071     str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
1072     ok(str == dest, "Expected str == dest, got %p\n", str);
1073     ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
1074     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1075
1076     /* try forward slashes */
1077     SetLastError(0xdeadbeef);
1078     lstrcpyA(dest, "control");
1079     str = PathCombineA(dest, "C:\\", "one/two/three\\");
1080     ok(str == dest, "Expected str == dest, got %p\n", str);
1081     ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
1082     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1083
1084     /* try a really weird directory */
1085     SetLastError(0xdeadbeef);
1086     lstrcpyA(dest, "control");
1087     str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
1088     ok(str == dest, "Expected str == dest, got %p\n", str);
1089     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1090     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1091
1092     /* try periods */
1093     SetLastError(0xdeadbeef);
1094     lstrcpyA(dest, "control");
1095     str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
1096     ok(str == dest, "Expected str == dest, got %p\n", str);
1097     ok(!lstrcmp(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
1098     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1099
1100     /* try .. as file */
1101     /* try forward slashes */
1102     SetLastError(0xdeadbeef);
1103     lstrcpyA(dest, "control");
1104     str = PathCombineA(dest, "C:\\", "..");
1105     ok(str == dest, "Expected str == dest, got %p\n", str);
1106     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
1107     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1108
1109     memset(too_long, 'a', LONG_LEN);
1110     too_long[LONG_LEN - 1] = '\0';
1111
1112     /* try a file longer than MAX_PATH */
1113     SetLastError(0xdeadbeef);
1114     lstrcpyA(dest, "control");
1115     str = PathCombineA(dest, "C:\\", too_long);
1116     todo_wine
1117     {
1118         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1119         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1120         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1121     }
1122
1123     /* try a directory longer than MAX_PATH */
1124     SetLastError(0xdeadbeef);
1125     lstrcpyA(dest, "control");
1126     str = PathCombineA(dest, too_long, "one\\two\\three");
1127     todo_wine
1128     {
1129         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1130         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1131         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1132     }
1133
1134     memset(one, 'b', HALF_LEN);
1135     memset(two, 'c', HALF_LEN);
1136     one[HALF_LEN - 1] = '\0';
1137     two[HALF_LEN - 1] = '\0';
1138
1139     /* destination string is longer than MAX_PATH, but not the constituent parts */
1140     SetLastError(0xdeadbeef);
1141     lstrcpyA(dest, "control");
1142     str = PathCombineA(dest, one, two);
1143     todo_wine
1144     {
1145         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1146         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1147     }
1148     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1149 }
1150
1151 static void test_PathAddBackslash(void)
1152 {
1153     LPSTR str;
1154     char path[MAX_PATH];
1155     char too_long[LONG_LEN];
1156
1157     /* try a NULL path */
1158     SetLastError(0xdeadbeef);
1159     str = PathAddBackslashA(NULL);
1160     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1161     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1162
1163     /* try an empty path */
1164     path[0] = '\0';
1165     SetLastError(0xdeadbeef);
1166     str = PathAddBackslashA(path);
1167     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1168     ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
1169     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1170
1171     /* try a relative path */
1172     lstrcpyA(path, "one\\two");
1173     SetLastError(0xdeadbeef);
1174     str = PathAddBackslashA(path);
1175     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1176     ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
1177     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1178
1179     /* try periods */
1180     lstrcpyA(path, "one\\..\\two");
1181     SetLastError(0xdeadbeef);
1182     str = PathAddBackslashA(path);
1183     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1184     ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
1185     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1186
1187     /* try just a space */
1188     lstrcpyA(path, " ");
1189     SetLastError(0xdeadbeef);
1190     str = PathAddBackslashA(path);
1191     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1192     ok(!lstrcmp(path, " \\"), "Expected  \\, got %s\n", path);
1193     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1194
1195     /* path already has backslash */
1196     lstrcpyA(path, "C:\\one\\");
1197     SetLastError(0xdeadbeef);
1198     str = PathAddBackslashA(path);
1199     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1200     ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
1201     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1202
1203     memset(too_long, 'a', LONG_LEN);
1204     too_long[LONG_LEN - 1] = '\0';
1205
1206     /* path is longer than MAX_PATH */
1207     SetLastError(0xdeadbeef);
1208     str = PathAddBackslashA(too_long);
1209     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1210     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1211 }
1212
1213 static void test_PathAppendA(void)
1214 {
1215     char path[MAX_PATH];
1216     char too_long[LONG_LEN];
1217     char one[HALF_LEN], two[HALF_LEN];
1218     BOOL res;
1219
1220     lstrcpy(path, "C:\\one");
1221
1222     /* try NULL pszMore */
1223     SetLastError(0xdeadbeef);
1224     res = PathAppendA(path, NULL);
1225     ok(!res, "Expected failure\n");
1226     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1227     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1228
1229     /* try empty pszMore */
1230     SetLastError(0xdeadbeef);
1231     res = PathAppendA(path, "");
1232     ok(res, "Expected success\n");
1233     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1234     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1235
1236     /* try NULL pszPath */
1237     SetLastError(0xdeadbeef);
1238     res = PathAppendA(NULL, "two\\three");
1239     ok(!res, "Expected failure\n");
1240     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1241
1242     /* try empty pszPath */
1243     path[0] = '\0';
1244     SetLastError(0xdeadbeef);
1245     res = PathAppendA(path, "two\\three");
1246     ok(res, "Expected success\n");
1247     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1248     ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
1249
1250     /* try empty pszPath and empty pszMore */
1251     path[0] = '\0';
1252     SetLastError(0xdeadbeef);
1253     res = PathAppendA(path, "");
1254     ok(res, "Expected success\n");
1255     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1256     ok(!lstrcmp(path, "\\"), "Expected \\, got %s\n", path);
1257
1258     /* try legit params */
1259     lstrcpy(path, "C:\\one");
1260     SetLastError(0xdeadbeef);
1261     res = PathAppendA(path, "two\\three");
1262     ok(res, "Expected success\n");
1263     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1264     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1265
1266     /* try pszPath with backslash after it */
1267     lstrcpy(path, "C:\\one\\");
1268     SetLastError(0xdeadbeef);
1269     res = PathAppendA(path, "two\\three");
1270     ok(res, "Expected success\n");
1271     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1272     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1273
1274     /* try pszMore with backslash before it */
1275     lstrcpy(path, "C:\\one");
1276     SetLastError(0xdeadbeef);
1277     res = PathAppendA(path, "\\two\\three");
1278     ok(res, "Expected success\n");
1279     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1280     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1281
1282     /* try pszMore with backslash after it */
1283     lstrcpy(path, "C:\\one");
1284     SetLastError(0xdeadbeef);
1285     res = PathAppendA(path, "two\\three\\");
1286     ok(res, "Expected success\n");
1287     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1288     ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
1289
1290     /* try spaces in pszPath */
1291     lstrcpy(path, "C: \\ one ");
1292     SetLastError(0xdeadbeef);
1293     res = PathAppendA(path, "two\\three");
1294     ok(res, "Expected success\n");
1295     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1296     ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
1297
1298     /* try spaces in pszMore */
1299     lstrcpy(path, "C:\\one");
1300     SetLastError(0xdeadbeef);
1301     res = PathAppendA(path, " two \\ three ");
1302     ok(res, "Expected success\n");
1303     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1304     ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
1305
1306     /* pszPath is too long */
1307     memset(too_long, 'a', LONG_LEN);
1308     too_long[LONG_LEN - 1] = '\0';
1309     SetLastError(0xdeadbeef);
1310     res = PathAppendA(too_long, "two\\three");
1311     todo_wine
1312     {
1313         ok(!res, "Expected failure\n");
1314         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1315         ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
1316     }
1317
1318     /* pszMore is too long */
1319     lstrcpy(path, "C:\\one");
1320     memset(too_long, 'a', LONG_LEN);
1321     too_long[LONG_LEN - 1] = '\0';
1322     SetLastError(0xdeadbeef);
1323     res = PathAppendA(path, too_long);
1324     todo_wine
1325     {
1326         ok(!res, "Expected failure\n");
1327         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1328         ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path));
1329     }
1330
1331     /* both params combined are too long */
1332     memset(one, 'a', HALF_LEN);
1333     one[HALF_LEN - 1] = '\0';
1334     memset(two, 'b', HALF_LEN);
1335     two[HALF_LEN - 1] = '\0';
1336     SetLastError(0xdeadbeef);
1337     res = PathAppendA(one, two);
1338     todo_wine
1339     {
1340         ok(!res, "Expected failure\n");
1341         ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one));
1342     }
1343     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1344 }
1345
1346 static void test_PathCanonicalizeA(void)
1347 {
1348     char dest[MAX_PATH];
1349     char too_long[LONG_LEN];
1350     BOOL res;
1351
1352     /* try a NULL source */
1353     lstrcpy(dest, "test");
1354     SetLastError(0xdeadbeef);
1355     res = PathCanonicalizeA(dest, NULL);
1356     ok(!res, "Expected failure\n");
1357     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1358        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1359     todo_wine
1360     {
1361         ok(!lstrcmp(dest, "test"), "Expected test, got %s\n", dest);
1362     }
1363
1364     /* try an empty source */
1365     lstrcpy(dest, "test");
1366     SetLastError(0xdeadbeef);
1367     res = PathCanonicalizeA(dest, "");
1368     ok(res, "Expected success\n");
1369     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1370     ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest);
1371
1372     /* try a NULL dest */
1373     SetLastError(0xdeadbeef);
1374     res = PathCanonicalizeA(NULL, "C:\\");
1375     ok(!res, "Expected failure\n");
1376     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1377        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1378
1379     /* try empty dest */
1380     dest[0] = '\0';
1381     SetLastError(0xdeadbeef);
1382     res = PathCanonicalizeA(dest, "C:\\");
1383     ok(res, "Expected success\n");
1384     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1385     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1386
1387     /* try non-empty dest */
1388     lstrcpy(dest, "test");
1389     SetLastError(0xdeadbeef);
1390     res = PathCanonicalizeA(dest, "C:\\");
1391     ok(res, "Expected success\n");
1392     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1393     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1394
1395     /* try a space for source */
1396     lstrcpy(dest, "test");
1397     SetLastError(0xdeadbeef);
1398     res = PathCanonicalizeA(dest, " ");
1399     ok(res, "Expected success\n");
1400     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1401     ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
1402
1403     /* try a relative path */
1404     lstrcpy(dest, "test");
1405     SetLastError(0xdeadbeef);
1406     res = PathCanonicalizeA(dest, "one\\two");
1407     ok(res, "Expected success\n");
1408     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1409     ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
1410
1411     /* try current dir and previous dir */
1412     lstrcpy(dest, "test");
1413     SetLastError(0xdeadbeef);
1414     res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
1415     ok(res, "Expected success\n");
1416     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1417     ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
1418
1419     /* try simple forward slashes */
1420     lstrcpy(dest, "test");
1421     SetLastError(0xdeadbeef);
1422     res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
1423     ok(res, "Expected success\n");
1424     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1425     ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
1426        "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
1427
1428     /* try simple forward slashes with same dir */
1429     lstrcpy(dest, "test");
1430     SetLastError(0xdeadbeef);
1431     res = PathCanonicalizeA(dest, "C:\\one/.\\two");
1432     ok(res, "Expected success\n");
1433     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1434     ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
1435
1436     /* try simple forward slashes with change dir */
1437     lstrcpy(dest, "test");
1438     SetLastError(0xdeadbeef);
1439     res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
1440     ok(res, "Expected success\n");
1441     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1442     ok(!lstrcmp(dest, "C:\\one/."), "Expected C:\\one/., got %s\n", dest);
1443
1444     /* try forward slashes with change dirs
1445      * NOTE: if there is a forward slash in between two backslashes,
1446      * everything in between the two backslashes is considered on dir
1447      */
1448     lstrcpy(dest, "test");
1449     SetLastError(0xdeadbeef);
1450     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
1451     ok(res, "Expected success\n");
1452     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1453     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
1454
1455     /* try src is too long */
1456     memset(too_long, 'a', LONG_LEN);
1457     too_long[LONG_LEN - 1] = '\0';
1458     lstrcpy(dest, "test");
1459     SetLastError(0xdeadbeef);
1460     res = PathCanonicalizeA(dest, too_long);
1461     todo_wine
1462     {
1463         ok(!res, "Expected failure\n");
1464         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1465     }
1466     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
1467 }
1468
1469 static void test_PathFindExtensionA(void)
1470 {
1471     LPSTR ext;
1472     char path[MAX_PATH];
1473     char too_long[LONG_LEN];
1474
1475     /* try a NULL path */
1476     SetLastError(0xdeadbeef);
1477     ext = PathFindExtensionA(NULL);
1478     ok(ext == NULL, "Expected NULL, got %p\n", ext);
1479     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1480
1481     /* try an empty path */
1482     path[0] = '\0';
1483     SetLastError(0xdeadbeef);
1484     ext = PathFindExtensionA(path);
1485     ok(ext == path, "Expected ext == path, got %p\n", ext);
1486     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1487     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1488
1489     /* try a path without an extension */
1490     lstrcpy(path, "file");
1491     SetLastError(0xdeadbeef);
1492     ext = PathFindExtensionA(path);
1493     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
1494     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1495     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1496
1497     /* try a path with an extension */
1498     lstrcpy(path, "file.txt");
1499     SetLastError(0xdeadbeef);
1500     ext = PathFindExtensionA(path);
1501     ok(ext == path + lstrlen("file"),
1502        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
1503     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
1504     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1505
1506     /* try a path with two extensions */
1507     lstrcpy(path, "file.txt.doc");
1508     SetLastError(0xdeadbeef);
1509     ext = PathFindExtensionA(path);
1510     ok(ext == path + lstrlen("file.txt"),
1511        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
1512     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
1513     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1514
1515     /* try a path longer than MAX_PATH without an extension*/
1516     memset(too_long, 'a', LONG_LEN);
1517     too_long[LONG_LEN - 1] = '\0';
1518     SetLastError(0xdeadbeef);
1519     ext = PathFindExtensionA(too_long);
1520     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
1521     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1522
1523     /* try a path longer than MAX_PATH with an extension*/
1524     memset(too_long, 'a', LONG_LEN);
1525     too_long[LONG_LEN - 1] = '\0';
1526     lstrcpy(too_long + 300, ".abcde");
1527     too_long[lstrlen(too_long)] = 'a';
1528     SetLastError(0xdeadbeef);
1529     ext = PathFindExtensionA(too_long);
1530     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1531     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
1532     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1533 }
1534
1535 static void test_PathBuildRootA(void)
1536 {
1537     LPSTR root;
1538     char path[10];
1539     char root_expected[26][4];
1540     char drive;
1541     int j;
1542
1543     /* set up the expected paths */
1544     for (drive = 'A'; drive <= 'Z'; drive++)
1545         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1546
1547     /* test the expected values */
1548     for (j = 0; j < 26; j++)
1549     {
1550         SetLastError(0xdeadbeef);
1551         lstrcpy(path, "aaaaaaaaa");
1552         root = PathBuildRootA(path, j);
1553         ok(root == path, "Expected root == path, got %p\n", root);
1554         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1555         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1556     }
1557
1558     /* test a negative drive number */
1559     SetLastError(0xdeadbeef);
1560     lstrcpy(path, "aaaaaaaaa");
1561     root = PathBuildRootA(path, -1);
1562     ok(root == path, "Expected root == path, got %p\n", root);
1563     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1564     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1565
1566     /* test a drive number greater than 25 */
1567     SetLastError(0xdeadbeef);
1568     lstrcpy(path, "aaaaaaaaa");
1569     root = PathBuildRootA(path, 26);
1570     ok(root == path, "Expected root == path, got %p\n", root);
1571     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1572     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1573
1574     /* length of path is less than 4 */
1575     SetLastError(0xdeadbeef);
1576     lstrcpy(path, "aa");
1577     root = PathBuildRootA(path, 0);
1578     ok(root == path, "Expected root == path, got %p\n", root);
1579     ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1580     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1581
1582     /* path is NULL */
1583     SetLastError(0xdeadbeef);
1584     root = PathBuildRootA(NULL, 0);
1585     ok(root == NULL, "Expected root == NULL, got %p\n", root);
1586     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1587 }
1588
1589 static void test_PathCommonPrefixA(void)
1590 {
1591     char path1[MAX_PATH], path2[MAX_PATH];
1592     char out[MAX_PATH];
1593     int count;
1594
1595     /* test NULL path1 */
1596     SetLastError(0xdeadbeef);
1597     lstrcpy(path2, "C:\\");
1598     lstrcpy(out, "aaa");
1599     count = PathCommonPrefixA(NULL, path2, out);
1600     ok(count == 0, "Expected 0, got %i\n", count);
1601     todo_wine
1602     {
1603         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1604     }
1605     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1606     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1607
1608     /* test NULL path2 */
1609     SetLastError(0xdeadbeef);
1610     lstrcpy(path1, "C:\\");
1611     lstrcpy(out, "aaa");
1612     count = PathCommonPrefixA(path1, NULL, out);
1613     ok(count == 0, "Expected 0, got %i\n", count);
1614     todo_wine
1615     {
1616         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1617     }
1618     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1619     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1620
1621     /* test empty path1 */
1622     SetLastError(0xdeadbeef);
1623     path1[0] = '\0';
1624     lstrcpy(path2, "C:\\");
1625     lstrcpy(out, "aaa");
1626     count = PathCommonPrefixA(path1, path2, out);
1627     ok(count == 0, "Expected 0, got %i\n", count);
1628     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1629     ok(lstrlen(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1630     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1631     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1632
1633     /* test empty path1 */
1634     SetLastError(0xdeadbeef);
1635     path2[0] = '\0';
1636     lstrcpy(path1, "C:\\");
1637     lstrcpy(out, "aaa");
1638     count = PathCommonPrefixA(path1, path2, out);
1639     ok(count == 0, "Expected 0, got %i\n", count);
1640     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1641     ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1642     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1643     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1644
1645     /* paths are legit, out is NULL */
1646     SetLastError(0xdeadbeef);
1647     lstrcpy(path1, "C:\\");
1648     lstrcpy(path2, "C:\\");
1649     count = PathCommonPrefixA(path1, path2, NULL);
1650     ok(count == 3, "Expected 3, got %i\n", count);
1651     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1652     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1653     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1654
1655     /* all parameters legit */
1656     SetLastError(0xdeadbeef);
1657     lstrcpy(path1, "C:\\");
1658     lstrcpy(path2, "C:\\");
1659     lstrcpy(out, "aaa");
1660     count = PathCommonPrefixA(path1, path2, out);
1661     ok(count == 3, "Expected 3, got %i\n", count);
1662     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1663     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1664     ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1665     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1666
1667     /* path1 and path2 not the same, but common prefix */
1668     SetLastError(0xdeadbeef);
1669     lstrcpy(path1, "C:\\one\\two");
1670     lstrcpy(path2, "C:\\one\\three");
1671     lstrcpy(out, "aaa");
1672     count = PathCommonPrefixA(path1, path2, out);
1673     ok(count == 6, "Expected 6, got %i\n", count);
1674     ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1675     ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1676     ok(!lstrcmp(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1677     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1678
1679     /* try . prefix */
1680     SetLastError(0xdeadbeef);
1681     lstrcpy(path1, "one\\.two");
1682     lstrcpy(path2, "one\\.three");
1683     lstrcpy(out, "aaa");
1684     count = PathCommonPrefixA(path1, path2, out);
1685     ok(count == 3, "Expected 3, got %i\n", count);
1686     ok(!lstrcmp(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1687     ok(!lstrcmp(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1688     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1689     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1690
1691     /* try .. prefix */
1692     SetLastError(0xdeadbeef);
1693     lstrcpy(path1, "one\\..two");
1694     lstrcpy(path2, "one\\..three");
1695     lstrcpy(out, "aaa");
1696     count = PathCommonPrefixA(path1, path2, out);
1697     ok(count == 3, "Expected 3, got %i\n", count);
1698     ok(!lstrcmp(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1699     ok(!lstrcmp(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1700     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1701     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1702
1703     /* try ... prefix */
1704     SetLastError(0xdeadbeef);
1705     lstrcpy(path1, "one\\...two");
1706     lstrcpy(path2, "one\\...three");
1707     lstrcpy(out, "aaa");
1708     count = PathCommonPrefixA(path1, path2, out);
1709     ok(count == 3, "Expected 3, got %i\n", count);
1710     ok(!lstrcmp(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1711     ok(!lstrcmp(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1712     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1713     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1714
1715     /* try .\ prefix */
1716     SetLastError(0xdeadbeef);
1717     lstrcpy(path1, "one\\.\\two");
1718     lstrcpy(path2, "one\\.\\three");
1719     lstrcpy(out, "aaa");
1720     count = PathCommonPrefixA(path1, path2, out);
1721     ok(count == 5, "Expected 5, got %i\n", count);
1722     ok(!lstrcmp(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1723     ok(!lstrcmp(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1724     ok(!lstrcmp(out, "one\\."), "Expected one\\., got %s\n", out);
1725     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1726
1727     /* try ..\ prefix */
1728     SetLastError(0xdeadbeef);
1729     lstrcpy(path1, "one\\..\\two");
1730     lstrcpy(path2, "one\\..\\three");
1731     lstrcpy(out, "aaa");
1732     count = PathCommonPrefixA(path1, path2, out);
1733     ok(count == 6, "Expected 6, got %i\n", count);
1734     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1735     ok(!lstrcmp(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1736     ok(!lstrcmp(out, "one\\.."), "Expected one\\.., got %s\n", out);
1737     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1738
1739     /* try ...\\ prefix */
1740     SetLastError(0xdeadbeef);
1741     lstrcpy(path1, "one\\...\\two");
1742     lstrcpy(path2, "one\\...\\three");
1743     lstrcpy(out, "aaa");
1744     count = PathCommonPrefixA(path1, path2, out);
1745     ok(count == 7, "Expected 7, got %i\n", count);
1746     ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1747     ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1748     ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1749     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1750
1751     /* try prefix that is not an msdn labeled prefix type */
1752     SetLastError(0xdeadbeef);
1753     lstrcpy(path1, "same");
1754     lstrcpy(path2, "same");
1755     lstrcpy(out, "aaa");
1756     count = PathCommonPrefixA(path1, path2, out);
1757     ok(count == 4, "Expected 4, got %i\n", count);
1758     ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1759     ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1760     ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1761     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1762
1763     /* try . after directory */
1764     SetLastError(0xdeadbeef);
1765     lstrcpy(path1, "one\\mid.\\two");
1766     lstrcpy(path2, "one\\mid.\\three");
1767     lstrcpy(out, "aaa");
1768     count = PathCommonPrefixA(path1, path2, out);
1769     ok(count == 8, "Expected 8, got %i\n", count);
1770     ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1771     ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1772     ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1773     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1774
1775     /* try . in the middle of a directory */
1776     SetLastError(0xdeadbeef);
1777     lstrcpy(path1, "one\\mid.end\\two");
1778     lstrcpy(path2, "one\\mid.end\\three");
1779     lstrcpy(out, "aaa");
1780     count = PathCommonPrefixA(path1, path2, out);
1781     ok(count == 11, "Expected 11, got %i\n", count);
1782     ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1783     ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1784     ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1785     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1786
1787     /* try comparing a .. with the expanded path */
1788     SetLastError(0xdeadbeef);
1789     lstrcpy(path1, "one\\..\\two");
1790     lstrcpy(path2, "two");
1791     lstrcpy(out, "aaa");
1792     count = PathCommonPrefixA(path1, path2, out);
1793     ok(count == 0, "Expected 0, got %i\n", count);
1794     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1795     ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1796     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1797     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1798 }
1799
1800 static void test_PathUnquoteSpaces(void)
1801 {
1802     int i;
1803     for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1804     {
1805         char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1806         WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1807         WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1808
1809         PathUnquoteSpacesA(path);
1810         ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1811            TEST_PATH_UNQUOTE_SPACES[i].path, path,
1812            TEST_PATH_UNQUOTE_SPACES[i].result);
1813
1814         PathUnquoteSpacesW(pathW);
1815         ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1816            TEST_PATH_UNQUOTE_SPACES[i].path);
1817         FreeWideString(pathW);
1818         FreeWideString(resultW);
1819         HeapFree(GetProcessHeap(), 0, path);
1820     }
1821 }
1822
1823 START_TEST(path)
1824 {
1825   hShlwapi = LoadLibraryA("shlwapi.dll");
1826   if (!hShlwapi) return;
1827
1828   test_UrlHash();
1829   test_UrlGetPart();
1830   test_UrlCanonicalize();
1831   test_UrlEscape();
1832   test_UrlCombine();
1833   test_UrlCreateFromPath();
1834   test_UrlIs();
1835   test_UrlUnescape();
1836
1837   test_PathSearchAndQualify();
1838   test_PathCreateFromUrl();
1839   test_PathIsUrl();
1840
1841   test_PathAddBackslash();
1842   test_PathMakePretty();
1843   test_PathMatchSpec();
1844
1845   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1846    * ordinal number in some native versions. Check this to prevent a crash.
1847    */
1848   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1849   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1850   {
1851     test_PathIsValidCharA();
1852
1853      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1854      if (pPathIsValidCharW) test_PathIsValidCharW();
1855   }
1856
1857   pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1858   if (pPathCombineW)
1859     test_PathCombineW();
1860
1861   test_PathCombineA();
1862   test_PathAppendA();
1863   test_PathCanonicalizeA();
1864   test_PathFindExtensionA();
1865   test_PathBuildRootA();
1866   test_PathCommonPrefixA();
1867   test_PathUnquoteSpaces();
1868 }