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