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