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