mshtml: Added beginning OnDataAvailable implementation.
[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
35 const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
36 const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
37 const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
38
39 typedef struct _TEST_URL_CANONICALIZE {
40     const char *url;
41     DWORD flags;
42     HRESULT expectret;
43     const char *expecturl;
44 } TEST_URL_CANONICALIZE;
45
46 const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
47     /*FIXME {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/"},*/
48     {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests"},
49     {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
50     {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
51     {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests"},
52     {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests"},
53     {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/"},
54     {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/"},
55     {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/"},
56     {"http://www.winehq.org/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/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"},
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/..#example", 0, S_OK, "http://www.winehq.org/#example"},
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", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example"},
66     {"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"},
67     {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar"},
68     {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/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_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
71     {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
72     {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
73     {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
74     {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar"},
75     {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar"},
76     {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar"},
77 };
78
79 typedef struct _TEST_URL_ESCAPE {
80     const char *url;
81     DWORD flags;
82     DWORD expectescaped;
83     HRESULT expectret;
84     const char *expecturl;
85 } TEST_URL_ESCAPE;
86
87 const TEST_URL_ESCAPE TEST_ESCAPE[] = {
88     {"http://www.winehq.org/tests0", 0, 0, S_OK, "http://www.winehq.org/tests0"},
89     {"http://www.winehq.org/tests1\n", 0, 0, S_OK, "http://www.winehq.org/tests1%0A"},
90     {"http://www.winehq.org/tests2\r", 0, 0, S_OK, "http://www.winehq.org/tests2%0D"},
91     {"http://www.winehq.org/tests3\r", URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, 0, S_OK, "http://www.winehq.org/tests3\r"},
92     {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
93     {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
94     {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
95
96     {"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
97     {"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
98     {"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
99     {"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
100     {"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
101     {"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
102     {"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
103     {"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
104     {"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
105     {"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"},
106     {"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
107     {"file:\\\\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:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
110     {"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"},
111     {"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"},
112     {"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"},
113     {"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"},
114     {"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"},
115
116     {"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"},
117     {"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"},
118     {"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"},
119     {"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"},
120     {"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"},
121     {"/foo/%5C", 0, 0, S_OK, "/foo/%5C"},
122     {"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"},
123
124     {"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"},
125     {"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"},
126     {"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
127     {"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
128     {"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"},
129     {"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
130     {"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
131     {"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"},
132     {"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"},
133     {"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
134     {"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
135     {"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
136     {"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
137     {"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"},
138     {"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"},
139     {"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"},
140
141     {"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"},
142     {"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
143     {"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
144
145     {"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"},
146     {"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"},
147     {"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"},
148     {"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"},
149     {"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"},
150     {"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"},
151     {"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"},
152     {"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"},
153     {"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"},
154
155     {"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
156     {"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
157     {"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"},
158
159     {"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
160     {"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"},
161     {"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"},
162     {"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"},
163     {"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"},
164     {"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"},
165     {"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"}
166 };
167
168 typedef struct _TEST_URL_COMBINE {
169     const char *url1;
170     const char *url2;
171     DWORD flags;
172     HRESULT expectret;
173     const char *expecturl;
174 } TEST_URL_COMBINE;
175
176 const TEST_URL_COMBINE TEST_COMBINE[] = {
177     {"http://www.winehq.org/tests", "tests1", 0, S_OK, "http://www.winehq.org/tests1"},
178     {"http://www.%77inehq.org/tests", "tests1", 0, S_OK, "http://www.%77inehq.org/tests1"},
179     /*FIXME {"http://www.winehq.org/tests", "../tests2", 0, S_OK, "http://www.winehq.org/tests2"},*/
180     {"http://www.winehq.org/tests/", "../tests3", 0, S_OK, "http://www.winehq.org/tests3"},
181     {"http://www.winehq.org/tests/test1", "test2", 0, S_OK, "http://www.winehq.org/tests/test2"},
182     {"http://www.winehq.org/tests/../tests", "tests4", 0, S_OK, "http://www.winehq.org/tests4"},
183     {"http://www.winehq.org/tests/../tests/", "tests5", 0, S_OK, "http://www.winehq.org/tests/tests5"},
184     {"http://www.winehq.org/tests/../tests/", "/tests6/..", 0, S_OK, "http://www.winehq.org/"},
185     {"http://www.winehq.org/tests/../tests/..", "tests7/..", 0, S_OK, "http://www.winehq.org/"},
186     {"http://www.winehq.org/tests/?query=x&return=y", "tests8", 0, S_OK, "http://www.winehq.org/tests/tests8"},
187     {"http://www.winehq.org/tests/#example", "tests9", 0, S_OK, "http://www.winehq.org/tests/tests9"},
188     {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."},
189     {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"},
190     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}
191 };
192
193 struct {
194     const char *path;
195     const char *url;
196     DWORD ret;
197 } TEST_URLFROMPATH [] = {
198     {"foo", "file:foo", S_OK},
199     {"foo\\bar", "file:foo/bar", S_OK},
200     {"\\foo\\bar", "file:///foo/bar", S_OK},
201     {"c:\\foo\\bar", "file:///c:/foo/bar", S_OK},
202     {"c:foo\\bar", "file:///c:foo/bar", S_OK},
203     {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK},
204     {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK},
205 #if 0
206     /* The following test fails on native shlwapi as distributed with Win95/98.
207      * Wine matches the behaviour of later versions.
208      */
209     {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE}
210 #endif
211 };
212
213 struct {
214     const char *url;
215     const char *path;
216     DWORD ret;
217 } TEST_PATHFROMURL[] = {
218     {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK},
219     {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK},
220     {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK},
221     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
222     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
223     {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK},
224     {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK},
225     {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK},
226     {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK},
227     {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK},
228     {"file://c:/foo/bar", "c:\\foo\\bar", S_OK},
229     {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK},
230     {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK},
231     {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK},
232     {"file:/foo/bar", "\\foo\\bar", S_OK},
233     {"file:/foo/bar/", "\\foo\\bar\\", S_OK},
234     {"file:foo/bar", "foo\\bar", S_OK},
235     {"file:c:/foo/bar", "c:\\foo\\bar", S_OK},
236     {"file:c|/foo/bar", "c:\\foo\\bar", S_OK},
237     {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK},
238     {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK},
239 /*    {"file:////c:/foo/foo%20bar", "c:\\foo\\foo%20bar", S_OK},*/
240
241     {"c:\\foo\\bar", NULL, E_INVALIDARG},
242     {"foo/bar", NULL, E_INVALIDARG},
243     {"http://foo/bar", NULL, E_INVALIDARG},
244
245 };
246
247 struct {
248     char url[30];
249     const char *expect;
250 } TEST_URL_UNESCAPE[] = {
251     {"file://foo/bar", "file://foo/bar"},
252     {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"}
253 };
254
255
256 struct {
257     const char *path;
258     BOOL expect;
259 } TEST_PATH_IS_URL[] = {
260     {"http://foo/bar", TRUE},
261     {"c:\\foo\\bar", FALSE},
262     {"foo://foo/bar", TRUE},
263     {"foo\\bar", FALSE},
264     {"foo.bar", FALSE},
265     {"bogusscheme:", TRUE},
266     {"http:partial", TRUE}
267 };
268
269 struct {
270     const char *url;
271     BOOL expectOpaque;
272     BOOL expectFile;
273 } TEST_URLIS_ATTRIBS[] = {
274     {   "ftp:",                                         FALSE,  FALSE   },
275     {   "http:",                                        FALSE,  FALSE   },
276     {   "gopher:",                                      FALSE,  FALSE   },
277     {   "mailto:",                                      TRUE,   FALSE   },
278     {   "news:",                                        FALSE,  FALSE   },
279     {   "nntp:",                                        FALSE,  FALSE   },
280     {   "telnet:",                                      FALSE,  FALSE   },
281     {   "wais:",                                        FALSE,  FALSE   },
282     {   "file:",                                        FALSE,  TRUE    },
283     {   "mk:",                                          FALSE,  FALSE   },
284     {   "https:",                                       FALSE,  FALSE   },
285     {   "shell:",                                       TRUE,   FALSE   },
286     {   "https:",                                       FALSE,  FALSE   },
287     {   "snews:",                                       FALSE,  FALSE   },
288     {   "local:",                                       FALSE,  FALSE   },
289     {   "javascript:",                                  TRUE,   FALSE   },
290     {   "vbscript:",                                    TRUE,   FALSE   },
291     {   "about:",                                       TRUE,   FALSE   },
292     {   "res:",                                         FALSE,  FALSE   },
293     {   "bogusscheme:",                                 FALSE,  FALSE   },
294     {   "file:\\\\e:\\b\\c",                            FALSE,  TRUE    },
295     {   "file://e:/b/c",                                FALSE,  TRUE    },
296     {   "http:partial",                                 FALSE,  FALSE   },
297     {   "mailto://www.winehq.org/test.html",            TRUE,   FALSE   },
298     {   "file:partial",                                 FALSE,  TRUE    }
299 };
300
301
302 static LPWSTR GetWideString(const char* szString)
303 {
304   LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
305   
306   MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
307
308   return wszString;
309 }
310
311 static void FreeWideString(LPWSTR wszString)
312 {
313    HeapFree(GetProcessHeap(), 0, wszString);
314 }
315
316 static void hash_url(const char* szUrl)
317 {
318   LPCSTR szTestUrl = szUrl;
319   LPWSTR wszTestUrl = GetWideString(szTestUrl);
320   
321   DWORD cbSize = sizeof(DWORD);
322   DWORD dwHash1, dwHash2;
323   ok(UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize) == S_OK, "UrlHashA didn't return S_OK\n");
324   ok(UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize) == S_OK, "UrlHashW didn't return S_OK\n");
325
326   FreeWideString(wszTestUrl);
327
328   ok(dwHash1 == dwHash2, "Hashes didn't compare\n");
329 }
330
331 static void test_UrlHash(void)
332 {
333   hash_url(TEST_URL_1);
334   hash_url(TEST_URL_2);
335   hash_url(TEST_URL_3);
336 }
337
338 static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const char* szExpected)
339 {
340   CHAR szPart[INTERNET_MAX_URL_LENGTH];
341   WCHAR wszPart[INTERNET_MAX_URL_LENGTH];
342   LPWSTR wszUrl = GetWideString(szUrl);
343   LPWSTR wszConvertedPart;
344
345   DWORD dwSize;
346
347   dwSize = INTERNET_MAX_URL_LENGTH;
348   ok( UrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartA for \"%s\" part 0x%08lx didn't return S_OK but \"%s\"\n", szUrl, dwPart, szPart);
349   dwSize = INTERNET_MAX_URL_LENGTH;
350   ok( UrlGetPartW(wszUrl, wszPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartW didn't return S_OK\n" );
351
352   wszConvertedPart = GetWideString(szPart);
353
354   ok(lstrcmpW(wszPart,wszConvertedPart)==0, "Strings didn't match between ascii and unicode UrlGetPart!\n");
355
356   FreeWideString(wszUrl);
357   FreeWideString(wszConvertedPart);
358
359   /* Note that v6.0 and later don't return '?' with the query */
360   ok(strcmp(szPart,szExpected)==0 ||
361      (*szExpected=='?' && !strcmp(szPart,szExpected+1)),
362          "Expected %s, but got %s\n", szExpected, szPart);
363 }
364
365 static void test_UrlGetPart(void)
366 {
367   test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost");
368   test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21");
369   test_url_part(TEST_URL_3, URL_PART_USERNAME, 0, "foo");
370   test_url_part(TEST_URL_3, URL_PART_PASSWORD, 0, "bar");
371   test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http");
372   test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y");
373 }
374
375 static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
376 {
377     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
378     DWORD dwEscaped;
379     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
380     WCHAR *urlW, *expected_urlW;
381     dwEscaped=INTERNET_MAX_URL_LENGTH;
382
383     ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
384     ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
385     
386     dwEscaped = INTERNET_MAX_URL_LENGTH;
387     urlW = GetWideString(szUrl);
388     expected_urlW = GetWideString(szExpectUrl);
389     ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
390     WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
391     ok(lstrcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
392     FreeWideString(urlW);
393     FreeWideString(expected_urlW);
394
395 }
396
397 static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
398 {
399     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
400     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
401     LPWSTR wszUrl = GetWideString(szUrl);
402     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
403     LPWSTR wszConvertedUrl;
404     
405     DWORD dwSize;
406     
407     dwSize = INTERNET_MAX_URL_LENGTH;
408     ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
409     ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08lx\n", dwExpectReturn);
410     ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08lx Expected %s, but got %s\n", dwFlags, szExpectUrl, szReturnUrl);
411
412     dwSize = INTERNET_MAX_URL_LENGTH;
413     ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
414     ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08lx\n", dwExpectReturn);
415     wszConvertedUrl = GetWideString(szReturnUrl);
416     ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n");
417     FreeWideString(wszConvertedUrl);
418     
419             
420     FreeWideString(wszUrl);
421     FreeWideString(wszExpectUrl);
422 }
423
424
425 static void test_UrlEscape(void)
426 {
427     unsigned int i;
428     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
429         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
430                               TEST_ESCAPE[i].expectret, TEST_ESCAPE[i].expecturl);
431     }
432 }
433
434 static void test_UrlCanonicalize(void)
435 {
436     unsigned int i;
437     for(i=0; i<sizeof(TEST_CANONICALIZE)/sizeof(TEST_CANONICALIZE[0]); i++) {
438         test_url_canonicalize(TEST_CANONICALIZE[i].url, TEST_CANONICALIZE[i].flags,
439                               TEST_CANONICALIZE[i].expectret, TEST_CANONICALIZE[i].expecturl);
440     }
441 }
442
443 static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
444 {
445     HRESULT hr;
446     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
447     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
448     LPWSTR wszUrl1 = GetWideString(szUrl1);
449     LPWSTR wszUrl2 = GetWideString(szUrl2);
450     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
451     LPWSTR wszConvertedUrl;
452
453     DWORD dwSize;
454     DWORD dwExpectLen = lstrlen(szExpectUrl);
455
456     hr = UrlCombineA(szUrl1, szUrl2, NULL, NULL, dwFlags);
457     ok(hr == E_INVALIDARG, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_INVALIDARG);
458     
459     dwSize = 0;
460     hr = UrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags);
461     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
462     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
463
464     dwSize--;
465     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
466     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
467     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
468     
469     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
470     ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
471     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
472     if(SUCCEEDED(hr)) {
473         ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
474     }
475
476     dwSize = 0;
477     hr = UrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags);
478     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
479     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
480
481     dwSize--;
482     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
483     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
484     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
485     
486     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
487     ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
488     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
489     if(SUCCEEDED(hr)) {
490         wszConvertedUrl = GetWideString(szReturnUrl);
491         ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n");
492         FreeWideString(wszConvertedUrl);
493     }
494
495     FreeWideString(wszUrl1);
496     FreeWideString(wszUrl2);
497     FreeWideString(wszExpectUrl);
498 }
499
500 static void test_UrlCombine(void)
501 {
502     unsigned int i;
503     for(i=0; i<sizeof(TEST_COMBINE)/sizeof(TEST_COMBINE[0]); i++) {
504         test_url_combine(TEST_COMBINE[i].url1, TEST_COMBINE[i].url2, TEST_COMBINE[i].flags,
505                          TEST_COMBINE[i].expectret, TEST_COMBINE[i].expecturl);
506     }
507 }
508
509 static void test_UrlCreateFromPath(void)
510 {
511     size_t i;
512     char ret_url[INTERNET_MAX_URL_LENGTH];
513     DWORD len, ret;
514     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
515     WCHAR *pathW, *urlW;
516
517     for(i = 0; i < sizeof(TEST_URLFROMPATH) / sizeof(TEST_URLFROMPATH[0]); i++) {
518         len = INTERNET_MAX_URL_LENGTH;
519         ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
520         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path %s\n", ret, TEST_URLFROMPATH[i].path);
521         ok(!lstrcmpi(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
522         ok(len == strlen(ret_url), "ret len %ld from path %s\n", len, TEST_URLFROMPATH[i].path);
523
524         len = INTERNET_MAX_URL_LENGTH;
525         pathW = GetWideString(TEST_URLFROMPATH[i].path);
526         urlW = GetWideString(TEST_URLFROMPATH[i].url);
527         ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
528         WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
529         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path L\"%s\", expected %08lx\n",
530            ret, TEST_URLFROMPATH[i].path, TEST_URLFROMPATH[i].ret);
531         ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n", ret_url, TEST_URLFROMPATH[i].url, TEST_URLFROMPATH[i].path);
532         ok(len == lstrlenW(ret_urlW), "ret len %ld from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
533         FreeWideString(urlW);
534         FreeWideString(pathW);
535     }
536 }
537
538 static void test_UrlIs(void)
539 {
540     BOOL ret;
541     size_t i;
542     WCHAR wurl[80];
543
544     for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
545         MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80);
546
547         ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL );
548         ok( ret == TEST_PATH_IS_URL[i].expect,
549             "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
550             TEST_PATH_IS_URL[i].expect );
551
552         ret = UrlIsW( wurl, URLIS_URL );
553         ok( ret == TEST_PATH_IS_URL[i].expect,
554             "returned %d from path (UrlIsW) %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
555             TEST_PATH_IS_URL[i].expect );
556     }
557     for(i = 0; i < sizeof(TEST_URLIS_ATTRIBS) / sizeof(TEST_URLIS_ATTRIBS[0]); i++) {
558         MultiByteToWideChar(CP_ACP, 0, TEST_URLIS_ATTRIBS[i].url, -1, wurl, 80);
559
560         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_OPAQUE);
561         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
562             "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
563             TEST_URLIS_ATTRIBS[i].expectOpaque );
564         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_FILEURL);
565         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
566             "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
567             TEST_URLIS_ATTRIBS[i].expectFile );
568
569         ret = UrlIsW( wurl, URLIS_OPAQUE);
570         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
571             "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
572             TEST_URLIS_ATTRIBS[i].expectOpaque );
573         ret = UrlIsW( wurl, URLIS_FILEURL);
574         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
575             "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
576             TEST_URLIS_ATTRIBS[i].expectFile );
577     }
578 }
579
580 static void test_UrlUnescape(void)
581 {
582     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
583     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
584     WCHAR *urlW, *expected_urlW; 
585     DWORD dwEscaped;
586     size_t i;
587     static char inplace[] = "file:///C:/Program%20Files";
588     static WCHAR inplaceW[] = {'f','i','l','e',':','/','/','/','C',':','/',
589                                'P','r','o','g','r','a','m','%','2','0','F','i','l','e','s',0};
590
591     for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) { 
592         dwEscaped=INTERNET_MAX_URL_LENGTH;
593         ok(UrlUnescapeA(TEST_URL_UNESCAPE[i].url, szReturnUrl, &dwEscaped, 0) == S_OK, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
594         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);
595
596         dwEscaped = INTERNET_MAX_URL_LENGTH;
597         urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
598         expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
599         ok(UrlUnescapeW(urlW, ret_urlW, &dwEscaped, 0) == S_OK, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
600         WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
601         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);
602         FreeWideString(urlW);
603         FreeWideString(expected_urlW);
604     }
605
606     dwEscaped = sizeof(inplace);
607     ok(UrlUnescapeA(inplace, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeA failed unexpectedly\n");
608
609     dwEscaped = sizeof(inplaceW);
610     ok(UrlUnescapeW(inplaceW, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeW failed unexpectedly\n");
611 }
612
613 static void test_PathSearchAndQualify(void)
614 {
615     WCHAR path1[] = {'c',':','\\','f','o','o',0};
616     WCHAR expect1[] = {'c',':','\\','f','o','o',0};
617     WCHAR path2[] = {'c',':','f','o','o',0};
618     WCHAR c_drive[] = {'c',':',0}; 
619     WCHAR foo[] = {'f','o','o',0}; 
620     WCHAR path3[] = {'\\','f','o','o',0};
621     WCHAR winini[] = {'w','i','n','.','i','n','i',0};
622     WCHAR out[MAX_PATH];
623     WCHAR cur_dir[MAX_PATH];
624     WCHAR dot[] = {'.',0};
625
626     /* c:\foo */
627     ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
628        "PathSearchAndQualify rets 0\n");
629     ok(!lstrcmpiW(out, expect1), "strings don't match\n");
630
631     /* c:foo */
632     ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
633        "PathSearchAndQualify rets 0\n");
634     GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
635     PathAddBackslashW(cur_dir);
636     lstrcatW(cur_dir, foo);
637     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
638
639     /* foo */
640     ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
641        "PathSearchAndQualify rets 0\n");
642     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
643     PathAddBackslashW(cur_dir);
644     lstrcatW(cur_dir, foo);
645     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
646
647     /* \foo */
648     ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
649        "PathSearchAndQualify rets 0\n");
650     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
651     lstrcpyW(cur_dir + 2, path3);
652     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
653
654     /* win.ini */
655     ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
656        "PathSearchAndQualify rets 0\n");
657     if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
658         GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
659     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
660
661 }
662
663 static void test_PathCreateFromUrl(void)
664 {
665     size_t i;
666     char ret_path[INTERNET_MAX_URL_LENGTH];
667     DWORD len, ret;
668     WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
669     WCHAR *pathW, *urlW;
670
671     for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
672         len = INTERNET_MAX_URL_LENGTH;
673         ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
674         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url %s\n", ret, TEST_PATHFROMURL[i].url);
675         if(TEST_PATHFROMURL[i].path) {
676            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);
677            ok(len == strlen(ret_path), "ret len %ld from url %s\n", len, TEST_PATHFROMURL[i].url);
678         }
679         len = INTERNET_MAX_URL_LENGTH;
680         pathW = GetWideString(TEST_PATHFROMURL[i].path);
681         urlW = GetWideString(TEST_PATHFROMURL[i].url);
682         ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
683         WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
684         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
685         if(TEST_PATHFROMURL[i].path) {
686             ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
687             ok(len == lstrlenW(ret_pathW), "ret len %ld from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
688         }
689         FreeWideString(urlW);
690         FreeWideString(pathW);
691     }
692 }
693
694
695 static void test_PathIsUrl(void)
696 {
697     size_t i;
698     BOOL ret;
699
700     for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
701         ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
702         ok(ret == TEST_PATH_IS_URL[i].expect,
703            "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
704            TEST_PATH_IS_URL[i].expect);
705     }
706 }
707
708 static const DWORD SHELL_charclass[] =
709 {
710     0x00000000, 0x00000000, 0x00000000, 0x00000000,
711     0x00000000, 0x00000000, 0x00000000, 0x00000000,
712     0x00000000, 0x00000000, 0x00000000, 0x00000000,
713     0x00000000, 0x00000000, 0x00000000, 0x00000000,
714     0x00000000, 0x00000000, 0x00000000, 0x00000000,
715     0x00000000, 0x00000000, 0x00000000, 0x00000000,
716     0x00000000, 0x00000000, 0x00000000, 0x00000000,
717     0x00000000, 0x00000000, 0x00000000, 0x00000000,
718     0x00000080, 0x00000100, 0x00000200, 0x00000100,
719     0x00000100, 0x00000100, 0x00000100, 0x00000100,
720     0x00000100, 0x00000100, 0x00000002, 0x00000100,
721     0x00000040, 0x00000100, 0x00000004, 0x00000000,
722     0x00000100, 0x00000100, 0x00000100, 0x00000100,
723     0x00000100, 0x00000100, 0x00000100, 0x00000100,
724     0x00000100, 0x00000100, 0x00000010, 0x00000020,
725     0x00000000, 0x00000100, 0x00000000, 0x00000001,
726     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
727     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
728     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
729     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
730     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
731     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
732     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
733     0x00000008, 0x00000100, 0x00000100, 0x00000100,
734     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
735     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
736     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
737     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
738     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
739     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
740     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
741     0x00000000, 0x00000100, 0x00000100
742 };
743
744 static void test_PathIsValidCharA(void)
745 {
746     BOOL ret;
747     unsigned int c;
748
749     ret = pPathIsValidCharA( 0x7f, 0 );
750     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
751
752     ret = pPathIsValidCharA( 0x7f, 1 );
753     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
754
755     for (c = 0; c < 0x7f; c++)
756     {
757         ret = pPathIsValidCharA( c, ~0U );
758         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
759              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
760              c, (DWORD)ret, SHELL_charclass[c] );
761     }
762
763     for (c = 0x7f; c <= 0xff; c++)
764     {
765         ret = pPathIsValidCharA( c, ~0U );
766         ok ( ret == 0x00000100,
767              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x00000100\n",
768              c, (DWORD)ret );
769     }
770 }
771
772 static void test_PathIsValidCharW(void)
773 {
774     BOOL ret;
775     unsigned int c, err_count = 0;
776
777     ret = pPathIsValidCharW( 0x7f, 0 );
778     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
779
780     ret = pPathIsValidCharW( 0x7f, 1 );
781     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
782
783     for (c = 0; c < 0x7f; c++)
784     {
785         ret = pPathIsValidCharW( c, ~0U );
786         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
787              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
788              c, (DWORD)ret, SHELL_charclass[c] );
789     }
790
791     for (c = 0x007f; c <= 0xffff; c++)
792     {
793         ret = pPathIsValidCharW( c, ~0U );
794         ok ( ret == 0x00000100,
795              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x00000100\n",
796              c, (DWORD)ret );
797         if (ret != 0x00000100)
798         {
799             if(++err_count > 100 ) {
800                 trace("skipping rest of PathIsValidCharW tests "
801                       "because of the current number of errors\n");
802                 break;
803             }
804         }
805     }
806 }
807
808 static void test_PathMakePretty(void)
809 {
810    char buff[MAX_PATH];
811
812    ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
813    buff[0] = '\0';
814    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
815
816    strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
817    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
818    ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
819        "PathMakePretty: Long UC name not changed\n");
820
821    strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
822    ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
823    ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
824        "PathMakePretty: Failed but modified path\n");
825
826    strcpy(buff, "TEST");
827    ok (PathMakePrettyA(buff) == TRUE,  "PathMakePretty: Short name failed\n");
828    ok (strcmp(buff, "Test") == 0,  "PathMakePretty: 1st char lowercased %s\n", buff);
829 }
830
831 static void test_PathMatchSpec(void)
832 {
833     static const char file[] = "c:\\foo\\bar\\filename.ext";
834     static const char spec1[] = ".ext";
835     static const char spec2[] = "*.ext";
836     static const char spec3[] = "*.ext ";
837     static const char spec4[] = "  *.ext";
838     static const char spec5[] = "* .ext";
839     static const char spec6[] = "*. ext";
840     static const char spec7[] = "* . ext";
841     static const char spec8[] = "*.e?t";
842     static const char spec9[] = "filename.ext";
843     static const char spec10[] = "*bar\\filename.ext";
844     static const char spec11[] = " foo; *.ext";
845     static const char spec12[] = "*.ext;*.bar";
846     static const char spec13[] = "*bar*";
847
848     ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
849     ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
850     ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
851     ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
852     todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
853     todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
854     ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
855     ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
856     ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
857     ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
858     ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
859     ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
860     ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
861 }
862
863
864 START_TEST(path)
865 {
866   hShlwapi = LoadLibraryA("shlwapi.dll");
867   if (!hShlwapi) return;
868
869   test_UrlHash();
870   test_UrlGetPart();
871   test_UrlCanonicalize();
872   test_UrlEscape();
873   test_UrlCombine();
874   test_UrlCreateFromPath();
875   test_UrlIs();
876   test_UrlUnescape();
877
878   test_PathSearchAndQualify();
879   test_PathCreateFromUrl();
880   test_PathIsUrl();
881
882   test_PathMakePretty();
883   test_PathMatchSpec();
884
885   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
886    * ordinal number in some native versions. Check this to prevent a crash.
887    */
888   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
889   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
890   {
891     test_PathIsValidCharA();
892
893      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
894      if (pPathIsValidCharW) test_PathIsValidCharW();
895   }
896 }