hhctrl.ocx: Added hhc parser.
[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    
956     wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
957
958     /* NULL test */
959     wszString = pPathCombineW(NULL, NULL, NULL);
960     ok (wszString == NULL, "Expected a NULL return\n");
961
962     /* Some NULL */
963     wszString = pPathCombineW(wszString2, NULL, NULL);
964     ok (wszString == NULL, "Expected a NULL return\n");
965  
966     HeapFree(GetProcessHeap(), 0, wszString2);
967 }
968
969 #define LONG_LEN (MAX_PATH * 2)
970 #define HALF_LEN (MAX_PATH / 2 + 1)
971
972 static void test_PathCombineA(void)
973 {
974     LPSTR str;
975     char dest[MAX_PATH];
976     char too_long[LONG_LEN];
977     char one[HALF_LEN], two[HALF_LEN];
978
979     /* try NULL dest */
980     SetLastError(0xdeadbeef);
981     str = PathCombineA(NULL, "C:\\", "one\\two\\three");
982     ok(str == NULL, "Expected NULL, got %p\n", str);
983     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
984
985     /* try NULL dest and NULL directory */
986     SetLastError(0xdeadbeef);
987     str = PathCombineA(NULL, NULL, "one\\two\\three");
988     ok(str == NULL, "Expected NULL, got %p\n", str);
989     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
990
991     /* try all NULL*/
992     SetLastError(0xdeadbeef);
993     str = PathCombineA(NULL, NULL, NULL);
994     ok(str == NULL, "Expected NULL, got %p\n", str);
995     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
996
997     /* try NULL file part */
998     SetLastError(0xdeadbeef);
999     lstrcpyA(dest, "control");
1000     str = PathCombineA(dest, "C:\\", NULL);
1001     ok(str == dest, "Expected str == dest, got %p\n", str);
1002     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
1003     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1004
1005     /* try empty file part */
1006     SetLastError(0xdeadbeef);
1007     lstrcpyA(dest, "control");
1008     str = PathCombineA(dest, "C:\\", "");
1009     ok(str == dest, "Expected str == dest, got %p\n", str);
1010     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
1011     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1012
1013     /* try empty directory and file part */
1014     SetLastError(0xdeadbeef);
1015     lstrcpyA(dest, "control");
1016     str = PathCombineA(dest, "", "");
1017     ok(str == dest, "Expected str == dest, got %p\n", str);
1018     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
1019     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1020
1021     /* try NULL directory */
1022     SetLastError(0xdeadbeef);
1023     lstrcpyA(dest, "control");
1024     str = PathCombineA(dest, NULL, "one\\two\\three");
1025     ok(str == dest, "Expected str == dest, got %p\n", str);
1026     ok(!lstrcmp(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
1027     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1028
1029     /* try NULL directory and empty file part */
1030     SetLastError(0xdeadbeef);
1031     lstrcpyA(dest, "control");
1032     str = PathCombineA(dest, NULL, "");
1033     ok(str == dest, "Expected str == dest, got %p\n", str);
1034     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
1035     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1036
1037     /* try NULL directory and file part */
1038     SetLastError(0xdeadbeef);
1039     lstrcpyA(dest, "control");
1040     str = PathCombineA(dest, NULL, NULL);
1041     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1042     todo_wine
1043     {
1044         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1045     }
1046     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1047
1048     /* try directory without backslash */
1049     SetLastError(0xdeadbeef);
1050     lstrcpyA(dest, "control");
1051     str = PathCombineA(dest, "C:", "one\\two\\three");
1052     ok(str == dest, "Expected str == dest, got %p\n", str);
1053     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1054     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1055
1056     /* try directory with backslash */
1057     SetLastError(0xdeadbeef);
1058     lstrcpyA(dest, "control");
1059     str = PathCombineA(dest, "C:\\", "one\\two\\three");
1060     ok(str == dest, "Expected str == dest, got %p\n", str);
1061     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1062     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1063
1064     /* try directory with backslash and file with prepended backslash */
1065     SetLastError(0xdeadbeef);
1066     lstrcpyA(dest, "control");
1067     str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
1068     ok(str == dest, "Expected str == dest, got %p\n", str);
1069     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1070     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1071
1072     /* try previous test, with backslash appended as well */
1073     SetLastError(0xdeadbeef);
1074     lstrcpyA(dest, "control");
1075     str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
1076     ok(str == dest, "Expected str == dest, got %p\n", str);
1077     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1078     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1079
1080     /* try a relative directory */
1081     SetLastError(0xdeadbeef);
1082     lstrcpyA(dest, "control");
1083     str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
1084     ok(str == dest, "Expected str == dest, got %p\n", str);
1085     ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
1086     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1087
1088     /* try forward slashes */
1089     SetLastError(0xdeadbeef);
1090     lstrcpyA(dest, "control");
1091     str = PathCombineA(dest, "C:\\", "one/two/three\\");
1092     ok(str == dest, "Expected str == dest, got %p\n", str);
1093     ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
1094     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1095
1096     /* try a really weird directory */
1097     SetLastError(0xdeadbeef);
1098     lstrcpyA(dest, "control");
1099     str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
1100     ok(str == dest, "Expected str == dest, got %p\n", str);
1101     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1102     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1103
1104     /* try periods */
1105     SetLastError(0xdeadbeef);
1106     lstrcpyA(dest, "control");
1107     str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
1108     ok(str == dest, "Expected str == dest, got %p\n", str);
1109     ok(!lstrcmp(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
1110     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1111
1112     /* try .. as file */
1113     /* try forward slashes */
1114     SetLastError(0xdeadbeef);
1115     lstrcpyA(dest, "control");
1116     str = PathCombineA(dest, "C:\\", "..");
1117     ok(str == dest, "Expected str == dest, got %p\n", str);
1118     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
1119     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1120
1121     memset(too_long, 'a', LONG_LEN);
1122     too_long[LONG_LEN - 1] = '\0';
1123
1124     /* try a file longer than MAX_PATH */
1125     SetLastError(0xdeadbeef);
1126     lstrcpyA(dest, "control");
1127     str = PathCombineA(dest, "C:\\", too_long);
1128     todo_wine
1129     {
1130         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1131         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1132         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1133     }
1134
1135     /* try a directory longer than MAX_PATH */
1136     SetLastError(0xdeadbeef);
1137     lstrcpyA(dest, "control");
1138     str = PathCombineA(dest, too_long, "one\\two\\three");
1139     todo_wine
1140     {
1141         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1142         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1143         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1144     }
1145
1146     memset(one, 'b', HALF_LEN);
1147     memset(two, 'c', HALF_LEN);
1148     one[HALF_LEN - 1] = '\0';
1149     two[HALF_LEN - 1] = '\0';
1150
1151     /* destination string is longer than MAX_PATH, but not the constituent parts */
1152     SetLastError(0xdeadbeef);
1153     lstrcpyA(dest, "control");
1154     str = PathCombineA(dest, one, two);
1155     todo_wine
1156     {
1157         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1158         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1159     }
1160     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1161 }
1162
1163 static void test_PathAddBackslash(void)
1164 {
1165     LPSTR str;
1166     char path[MAX_PATH];
1167     char too_long[LONG_LEN];
1168
1169     /* try a NULL path */
1170     SetLastError(0xdeadbeef);
1171     str = PathAddBackslashA(NULL);
1172     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1173     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1174
1175     /* try an empty path */
1176     path[0] = '\0';
1177     SetLastError(0xdeadbeef);
1178     str = PathAddBackslashA(path);
1179     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1180     ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
1181     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1182
1183     /* try a relative path */
1184     lstrcpyA(path, "one\\two");
1185     SetLastError(0xdeadbeef);
1186     str = PathAddBackslashA(path);
1187     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1188     ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
1189     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1190
1191     /* try periods */
1192     lstrcpyA(path, "one\\..\\two");
1193     SetLastError(0xdeadbeef);
1194     str = PathAddBackslashA(path);
1195     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1196     ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
1197     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1198
1199     /* try just a space */
1200     lstrcpyA(path, " ");
1201     SetLastError(0xdeadbeef);
1202     str = PathAddBackslashA(path);
1203     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1204     ok(!lstrcmp(path, " \\"), "Expected  \\, got %s\n", path);
1205     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1206
1207     /* path already has backslash */
1208     lstrcpyA(path, "C:\\one\\");
1209     SetLastError(0xdeadbeef);
1210     str = PathAddBackslashA(path);
1211     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1212     ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
1213     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1214
1215     memset(too_long, 'a', LONG_LEN);
1216     too_long[LONG_LEN - 1] = '\0';
1217
1218     /* path is longer than MAX_PATH */
1219     SetLastError(0xdeadbeef);
1220     str = PathAddBackslashA(too_long);
1221     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1222     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1223 }
1224
1225 static void test_PathAppendA(void)
1226 {
1227     char path[MAX_PATH];
1228     char too_long[LONG_LEN];
1229     char one[HALF_LEN], two[HALF_LEN];
1230     BOOL res;
1231
1232     lstrcpy(path, "C:\\one");
1233
1234     /* try NULL pszMore */
1235     SetLastError(0xdeadbeef);
1236     res = PathAppendA(path, NULL);
1237     ok(!res, "Expected failure\n");
1238     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1239     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1240
1241     /* try empty pszMore */
1242     SetLastError(0xdeadbeef);
1243     res = PathAppendA(path, "");
1244     ok(res, "Expected success\n");
1245     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1246     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1247
1248     /* try NULL pszPath */
1249     SetLastError(0xdeadbeef);
1250     res = PathAppendA(NULL, "two\\three");
1251     ok(!res, "Expected failure\n");
1252     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1253
1254     /* try empty pszPath */
1255     path[0] = '\0';
1256     SetLastError(0xdeadbeef);
1257     res = PathAppendA(path, "two\\three");
1258     ok(res, "Expected success\n");
1259     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1260     ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
1261
1262     /* try empty pszPath and empty pszMore */
1263     path[0] = '\0';
1264     SetLastError(0xdeadbeef);
1265     res = PathAppendA(path, "");
1266     ok(res, "Expected success\n");
1267     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1268     ok(!lstrcmp(path, "\\"), "Expected \\, got %s\n", path);
1269
1270     /* try legit params */
1271     lstrcpy(path, "C:\\one");
1272     SetLastError(0xdeadbeef);
1273     res = PathAppendA(path, "two\\three");
1274     ok(res, "Expected success\n");
1275     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1276     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1277
1278     /* try pszPath with backslash after it */
1279     lstrcpy(path, "C:\\one\\");
1280     SetLastError(0xdeadbeef);
1281     res = PathAppendA(path, "two\\three");
1282     ok(res, "Expected success\n");
1283     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1284     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1285
1286     /* try pszMore with backslash before it */
1287     lstrcpy(path, "C:\\one");
1288     SetLastError(0xdeadbeef);
1289     res = PathAppendA(path, "\\two\\three");
1290     ok(res, "Expected success\n");
1291     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1292     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1293
1294     /* try pszMore with backslash after it */
1295     lstrcpy(path, "C:\\one");
1296     SetLastError(0xdeadbeef);
1297     res = PathAppendA(path, "two\\three\\");
1298     ok(res, "Expected success\n");
1299     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1300     ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
1301
1302     /* try spaces in pszPath */
1303     lstrcpy(path, "C: \\ one ");
1304     SetLastError(0xdeadbeef);
1305     res = PathAppendA(path, "two\\three");
1306     ok(res, "Expected success\n");
1307     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1308     ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
1309
1310     /* try spaces in pszMore */
1311     lstrcpy(path, "C:\\one");
1312     SetLastError(0xdeadbeef);
1313     res = PathAppendA(path, " two \\ three ");
1314     ok(res, "Expected success\n");
1315     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1316     ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
1317
1318     /* pszPath is too long */
1319     memset(too_long, 'a', LONG_LEN);
1320     too_long[LONG_LEN - 1] = '\0';
1321     SetLastError(0xdeadbeef);
1322     res = PathAppendA(too_long, "two\\three");
1323     todo_wine
1324     {
1325         ok(!res, "Expected failure\n");
1326         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1327         ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
1328     }
1329
1330     /* pszMore is too long */
1331     lstrcpy(path, "C:\\one");
1332     memset(too_long, 'a', LONG_LEN);
1333     too_long[LONG_LEN - 1] = '\0';
1334     SetLastError(0xdeadbeef);
1335     res = PathAppendA(path, too_long);
1336     todo_wine
1337     {
1338         ok(!res, "Expected failure\n");
1339         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1340         ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path));
1341     }
1342
1343     /* both params combined are too long */
1344     memset(one, 'a', HALF_LEN);
1345     one[HALF_LEN - 1] = '\0';
1346     memset(two, 'b', HALF_LEN);
1347     two[HALF_LEN - 1] = '\0';
1348     SetLastError(0xdeadbeef);
1349     res = PathAppendA(one, two);
1350     todo_wine
1351     {
1352         ok(!res, "Expected failure\n");
1353         ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one));
1354     }
1355     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1356 }
1357
1358 static void test_PathCanonicalizeA(void)
1359 {
1360     char dest[MAX_PATH];
1361     char too_long[LONG_LEN];
1362     BOOL res;
1363
1364     /* try a NULL source */
1365     lstrcpy(dest, "test");
1366     SetLastError(0xdeadbeef);
1367     res = PathCanonicalizeA(dest, NULL);
1368     ok(!res, "Expected failure\n");
1369     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1370        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1371     todo_wine
1372     {
1373         ok(!lstrcmp(dest, "test"), "Expected test, got %s\n", dest);
1374     }
1375
1376     /* try an empty source */
1377     lstrcpy(dest, "test");
1378     SetLastError(0xdeadbeef);
1379     res = PathCanonicalizeA(dest, "");
1380     ok(res, "Expected success\n");
1381     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1382     ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest);
1383
1384     /* try a NULL dest */
1385     SetLastError(0xdeadbeef);
1386     res = PathCanonicalizeA(NULL, "C:\\");
1387     ok(!res, "Expected failure\n");
1388     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1389        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1390
1391     /* try empty dest */
1392     dest[0] = '\0';
1393     SetLastError(0xdeadbeef);
1394     res = PathCanonicalizeA(dest, "C:\\");
1395     ok(res, "Expected success\n");
1396     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1397     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1398
1399     /* try non-empty dest */
1400     lstrcpy(dest, "test");
1401     SetLastError(0xdeadbeef);
1402     res = PathCanonicalizeA(dest, "C:\\");
1403     ok(res, "Expected success\n");
1404     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1405     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1406
1407     /* try a space for source */
1408     lstrcpy(dest, "test");
1409     SetLastError(0xdeadbeef);
1410     res = PathCanonicalizeA(dest, " ");
1411     ok(res, "Expected success\n");
1412     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1413     ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
1414
1415     /* try a relative path */
1416     lstrcpy(dest, "test");
1417     SetLastError(0xdeadbeef);
1418     res = PathCanonicalizeA(dest, "one\\two");
1419     ok(res, "Expected success\n");
1420     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1421     ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
1422
1423     /* try current dir and previous dir */
1424     lstrcpy(dest, "test");
1425     SetLastError(0xdeadbeef);
1426     res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
1427     ok(res, "Expected success\n");
1428     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1429     ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
1430
1431     /* try simple forward slashes */
1432     lstrcpy(dest, "test");
1433     SetLastError(0xdeadbeef);
1434     res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
1435     ok(res, "Expected success\n");
1436     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1437     ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
1438        "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
1439
1440     /* try simple forward slashes with same dir */
1441     lstrcpy(dest, "test");
1442     SetLastError(0xdeadbeef);
1443     res = PathCanonicalizeA(dest, "C:\\one/.\\two");
1444     ok(res, "Expected success\n");
1445     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1446     ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
1447
1448     /* try simple forward slashes with change dir */
1449     lstrcpy(dest, "test");
1450     SetLastError(0xdeadbeef);
1451     res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
1452     ok(res, "Expected success\n");
1453     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1454     ok(!lstrcmp(dest, "C:\\one/."), "Expected C:\\one/., got %s\n", dest);
1455
1456     /* try forward slashes with change dirs
1457      * NOTE: if there is a forward slash in between two backslashes,
1458      * everything in between the two backslashes is considered on dir
1459      */
1460     lstrcpy(dest, "test");
1461     SetLastError(0xdeadbeef);
1462     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
1463     ok(res, "Expected success\n");
1464     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1465     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
1466
1467     /* try src is too long */
1468     memset(too_long, 'a', LONG_LEN);
1469     too_long[LONG_LEN - 1] = '\0';
1470     lstrcpy(dest, "test");
1471     SetLastError(0xdeadbeef);
1472     res = PathCanonicalizeA(dest, too_long);
1473     todo_wine
1474     {
1475         ok(!res, "Expected failure\n");
1476         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1477     }
1478     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
1479 }
1480
1481 static void test_PathFindExtensionA(void)
1482 {
1483     LPSTR ext;
1484     char path[MAX_PATH];
1485     char too_long[LONG_LEN];
1486
1487     /* try a NULL path */
1488     SetLastError(0xdeadbeef);
1489     ext = PathFindExtensionA(NULL);
1490     ok(ext == NULL, "Expected NULL, got %p\n", ext);
1491     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1492
1493     /* try an empty path */
1494     path[0] = '\0';
1495     SetLastError(0xdeadbeef);
1496     ext = PathFindExtensionA(path);
1497     ok(ext == path, "Expected ext == path, got %p\n", ext);
1498     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1499     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1500
1501     /* try a path without an extension */
1502     lstrcpy(path, "file");
1503     SetLastError(0xdeadbeef);
1504     ext = PathFindExtensionA(path);
1505     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
1506     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1507     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1508
1509     /* try a path with an extension */
1510     lstrcpy(path, "file.txt");
1511     SetLastError(0xdeadbeef);
1512     ext = PathFindExtensionA(path);
1513     ok(ext == path + lstrlen("file"),
1514        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
1515     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
1516     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1517
1518     /* try a path with two extensions */
1519     lstrcpy(path, "file.txt.doc");
1520     SetLastError(0xdeadbeef);
1521     ext = PathFindExtensionA(path);
1522     ok(ext == path + lstrlen("file.txt"),
1523        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
1524     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
1525     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1526
1527     /* try a path longer than MAX_PATH without an extension*/
1528     memset(too_long, 'a', LONG_LEN);
1529     too_long[LONG_LEN - 1] = '\0';
1530     SetLastError(0xdeadbeef);
1531     ext = PathFindExtensionA(too_long);
1532     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
1533     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1534
1535     /* try a path longer than MAX_PATH with an extension*/
1536     memset(too_long, 'a', LONG_LEN);
1537     too_long[LONG_LEN - 1] = '\0';
1538     lstrcpy(too_long + 300, ".abcde");
1539     too_long[lstrlen(too_long)] = 'a';
1540     SetLastError(0xdeadbeef);
1541     ext = PathFindExtensionA(too_long);
1542     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1543     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
1544     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1545 }
1546
1547 static void test_PathBuildRootA(void)
1548 {
1549     LPSTR root;
1550     char path[10];
1551     char root_expected[26][4];
1552     char drive;
1553     int j;
1554
1555     /* set up the expected paths */
1556     for (drive = 'A'; drive <= 'Z'; drive++)
1557         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1558
1559     /* test the expected values */
1560     for (j = 0; j < 26; j++)
1561     {
1562         SetLastError(0xdeadbeef);
1563         lstrcpy(path, "aaaaaaaaa");
1564         root = PathBuildRootA(path, j);
1565         ok(root == path, "Expected root == path, got %p\n", root);
1566         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1567         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1568     }
1569
1570     /* test a negative drive number */
1571     SetLastError(0xdeadbeef);
1572     lstrcpy(path, "aaaaaaaaa");
1573     root = PathBuildRootA(path, -1);
1574     ok(root == path, "Expected root == path, got %p\n", root);
1575     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1576     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1577
1578     /* test a drive number greater than 25 */
1579     SetLastError(0xdeadbeef);
1580     lstrcpy(path, "aaaaaaaaa");
1581     root = PathBuildRootA(path, 26);
1582     ok(root == path, "Expected root == path, got %p\n", root);
1583     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1584     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1585
1586     /* length of path is less than 4 */
1587     SetLastError(0xdeadbeef);
1588     lstrcpy(path, "aa");
1589     root = PathBuildRootA(path, 0);
1590     ok(root == path, "Expected root == path, got %p\n", root);
1591     ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1592     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1593
1594     /* path is NULL */
1595     SetLastError(0xdeadbeef);
1596     root = PathBuildRootA(NULL, 0);
1597     ok(root == NULL, "Expected root == NULL, got %p\n", root);
1598     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1599 }
1600
1601 static void test_PathCommonPrefixA(void)
1602 {
1603     char path1[MAX_PATH], path2[MAX_PATH];
1604     char out[MAX_PATH];
1605     int count;
1606
1607     /* test NULL path1 */
1608     SetLastError(0xdeadbeef);
1609     lstrcpy(path2, "C:\\");
1610     lstrcpy(out, "aaa");
1611     count = PathCommonPrefixA(NULL, path2, out);
1612     ok(count == 0, "Expected 0, got %i\n", count);
1613     todo_wine
1614     {
1615         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1616     }
1617     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1618     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1619
1620     /* test NULL path2 */
1621     SetLastError(0xdeadbeef);
1622     lstrcpy(path1, "C:\\");
1623     lstrcpy(out, "aaa");
1624     count = PathCommonPrefixA(path1, NULL, out);
1625     ok(count == 0, "Expected 0, got %i\n", count);
1626     todo_wine
1627     {
1628         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1629     }
1630     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1631     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1632
1633     /* test empty path1 */
1634     SetLastError(0xdeadbeef);
1635     path1[0] = '\0';
1636     lstrcpy(path2, "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(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1642     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1643     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1644
1645     /* test empty path1 */
1646     SetLastError(0xdeadbeef);
1647     path2[0] = '\0';
1648     lstrcpy(path1, "C:\\");
1649     lstrcpy(out, "aaa");
1650     count = PathCommonPrefixA(path1, path2, out);
1651     ok(count == 0, "Expected 0, got %i\n", count);
1652     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1653     ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1654     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1655     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1656
1657     /* paths are legit, out is NULL */
1658     SetLastError(0xdeadbeef);
1659     lstrcpy(path1, "C:\\");
1660     lstrcpy(path2, "C:\\");
1661     count = PathCommonPrefixA(path1, path2, NULL);
1662     ok(count == 3, "Expected 3, got %i\n", count);
1663     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1664     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1665     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1666
1667     /* all parameters legit */
1668     SetLastError(0xdeadbeef);
1669     lstrcpy(path1, "C:\\");
1670     lstrcpy(path2, "C:\\");
1671     lstrcpy(out, "aaa");
1672     count = PathCommonPrefixA(path1, path2, out);
1673     ok(count == 3, "Expected 3, got %i\n", count);
1674     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1675     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1676     ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1677     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1678
1679     /* path1 and path2 not the same, but common prefix */
1680     SetLastError(0xdeadbeef);
1681     lstrcpy(path1, "C:\\one\\two");
1682     lstrcpy(path2, "C:\\one\\three");
1683     lstrcpy(out, "aaa");
1684     count = PathCommonPrefixA(path1, path2, out);
1685     ok(count == 6, "Expected 6, got %i\n", count);
1686     ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1687     ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1688     ok(!lstrcmp(out, "C:\\one"), "Expected C:\\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 == 3, "Expected 3, 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 == 5, "Expected 5, 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 == 6, "Expected 6, 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 */
1752     SetLastError(0xdeadbeef);
1753     lstrcpy(path1, "one\\...\\two");
1754     lstrcpy(path2, "one\\...\\three");
1755     lstrcpy(out, "aaa");
1756     count = PathCommonPrefixA(path1, path2, out);
1757     ok(count == 7, "Expected 7, got %i\n", count);
1758     ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1759     ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1760     ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1761     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1762
1763     /* try prefix that is not an msdn labeled prefix type */
1764     SetLastError(0xdeadbeef);
1765     lstrcpy(path1, "same");
1766     lstrcpy(path2, "same");
1767     lstrcpy(out, "aaa");
1768     count = PathCommonPrefixA(path1, path2, out);
1769     ok(count == 4, "Expected 4, got %i\n", count);
1770     ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1771     ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1772     ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1773     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1774
1775     /* try . after directory */
1776     SetLastError(0xdeadbeef);
1777     lstrcpy(path1, "one\\mid.\\two");
1778     lstrcpy(path2, "one\\mid.\\three");
1779     lstrcpy(out, "aaa");
1780     count = PathCommonPrefixA(path1, path2, out);
1781     ok(count == 8, "Expected 8, got %i\n", count);
1782     ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1783     ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1784     ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1785     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1786
1787     /* try . in the middle of a directory */
1788     SetLastError(0xdeadbeef);
1789     lstrcpy(path1, "one\\mid.end\\two");
1790     lstrcpy(path2, "one\\mid.end\\three");
1791     lstrcpy(out, "aaa");
1792     count = PathCommonPrefixA(path1, path2, out);
1793     ok(count == 11, "Expected 11, got %i\n", count);
1794     ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1795     ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1796     ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1797     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1798
1799     /* try comparing a .. with the expanded path */
1800     SetLastError(0xdeadbeef);
1801     lstrcpy(path1, "one\\..\\two");
1802     lstrcpy(path2, "two");
1803     lstrcpy(out, "aaa");
1804     count = PathCommonPrefixA(path1, path2, out);
1805     ok(count == 0, "Expected 0, got %i\n", count);
1806     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1807     ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1808     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1809     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1810 }
1811
1812 static void test_PathUnquoteSpaces(void)
1813 {
1814     int i;
1815     for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1816     {
1817         char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1818         WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1819         WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1820
1821         PathUnquoteSpacesA(path);
1822         ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1823            TEST_PATH_UNQUOTE_SPACES[i].path, path,
1824            TEST_PATH_UNQUOTE_SPACES[i].result);
1825
1826         PathUnquoteSpacesW(pathW);
1827         ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1828            TEST_PATH_UNQUOTE_SPACES[i].path);
1829         FreeWideString(pathW);
1830         FreeWideString(resultW);
1831         HeapFree(GetProcessHeap(), 0, path);
1832     }
1833 }
1834
1835 START_TEST(path)
1836 {
1837   hShlwapi = LoadLibraryA("shlwapi.dll");
1838   if (!hShlwapi) return;
1839
1840   test_UrlHash();
1841   test_UrlGetPart();
1842   test_UrlCanonicalize();
1843   test_UrlEscape();
1844   test_UrlCombine();
1845   test_UrlCreateFromPath();
1846   test_UrlIs();
1847   test_UrlUnescape();
1848
1849   test_PathSearchAndQualify();
1850   test_PathCreateFromUrl();
1851   test_PathIsUrl();
1852
1853   test_PathAddBackslash();
1854   test_PathMakePretty();
1855   test_PathMatchSpec();
1856
1857   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1858    * ordinal number in some native versions. Check this to prevent a crash.
1859    */
1860   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1861   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1862   {
1863     test_PathIsValidCharA();
1864
1865      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1866      if (pPathIsValidCharW) test_PathIsValidCharW();
1867   }
1868
1869   pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1870   if (pPathCombineW)
1871     test_PathCombineW();
1872
1873   test_PathCombineA();
1874   test_PathAppendA();
1875   test_PathCanonicalizeA();
1876   test_PathFindExtensionA();
1877   test_PathBuildRootA();
1878   test_PathCommonPrefixA();
1879   test_PathUnquoteSpaces();
1880 }