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