kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[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
589     for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) { 
590         dwEscaped=INTERNET_MAX_URL_LENGTH;
591         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);
592         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);
593
594         dwEscaped = INTERNET_MAX_URL_LENGTH;
595         urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
596         expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
597         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);
598         WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
599         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);
600         FreeWideString(urlW);
601         FreeWideString(expected_urlW);
602     }
603
604 }
605
606 static void test_PathSearchAndQualify(void)
607 {
608     WCHAR path1[] = {'c',':','\\','f','o','o',0};
609     WCHAR expect1[] = {'c',':','\\','f','o','o',0};
610     WCHAR path2[] = {'c',':','f','o','o',0};
611     WCHAR c_drive[] = {'c',':',0}; 
612     WCHAR foo[] = {'f','o','o',0}; 
613     WCHAR path3[] = {'\\','f','o','o',0};
614     WCHAR winini[] = {'w','i','n','.','i','n','i',0};
615     WCHAR out[MAX_PATH];
616     WCHAR cur_dir[MAX_PATH];
617     WCHAR dot[] = {'.',0};
618
619     /* c:\foo */
620     ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
621        "PathSearchAndQualify rets 0\n");
622     ok(!lstrcmpiW(out, expect1), "strings don't match\n");
623
624     /* c:foo */
625     ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
626        "PathSearchAndQualify rets 0\n");
627     GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
628     PathAddBackslashW(cur_dir);
629     strcatW(cur_dir, foo);
630     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
631
632     /* foo */
633     ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
634        "PathSearchAndQualify rets 0\n");
635     GetFullPathNameW(dot, 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(path3, out, MAX_PATH) != 0,
642        "PathSearchAndQualify rets 0\n");
643     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
644     strcpyW(cur_dir + 2, path3);
645     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
646
647     /* win.ini */
648     ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
649        "PathSearchAndQualify rets 0\n");
650     if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
651         GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
652     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
653
654 }
655
656 static void test_PathCreateFromUrl(void)
657 {
658     size_t i;
659     char ret_path[INTERNET_MAX_URL_LENGTH];
660     DWORD len, ret;
661     WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
662     WCHAR *pathW, *urlW;
663
664     for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
665         len = INTERNET_MAX_URL_LENGTH;
666         ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
667         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url %s\n", ret, TEST_PATHFROMURL[i].url);
668         if(TEST_PATHFROMURL[i].path) {
669            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);
670            ok(len == strlen(ret_path), "ret len %ld from url %s\n", len, TEST_PATHFROMURL[i].url);
671         }
672         len = INTERNET_MAX_URL_LENGTH;
673         pathW = GetWideString(TEST_PATHFROMURL[i].path);
674         urlW = GetWideString(TEST_PATHFROMURL[i].url);
675         ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
676         WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
677         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
678         if(TEST_PATHFROMURL[i].path) {
679             ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
680             ok(len == strlenW(ret_pathW), "ret len %ld from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
681         }
682         FreeWideString(urlW);
683         FreeWideString(pathW);
684     }
685 }
686
687
688 static void test_PathIsUrl(void)
689 {
690     size_t i;
691     BOOL ret;
692
693     for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
694         ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
695         ok(ret == TEST_PATH_IS_URL[i].expect,
696            "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
697            TEST_PATH_IS_URL[i].expect);
698     }
699 }
700
701 static const DWORD SHELL_charclass[] =
702 {
703     0x00000000, 0x00000000, 0x00000000, 0x00000000,
704     0x00000000, 0x00000000, 0x00000000, 0x00000000,
705     0x00000000, 0x00000000, 0x00000000, 0x00000000,
706     0x00000000, 0x00000000, 0x00000000, 0x00000000,
707     0x00000000, 0x00000000, 0x00000000, 0x00000000,
708     0x00000000, 0x00000000, 0x00000000, 0x00000000,
709     0x00000000, 0x00000000, 0x00000000, 0x00000000,
710     0x00000000, 0x00000000, 0x00000000, 0x00000000,
711     0x00000080, 0x00000100, 0x00000200, 0x00000100,
712     0x00000100, 0x00000100, 0x00000100, 0x00000100,
713     0x00000100, 0x00000100, 0x00000002, 0x00000100,
714     0x00000040, 0x00000100, 0x00000004, 0x00000000,
715     0x00000100, 0x00000100, 0x00000100, 0x00000100,
716     0x00000100, 0x00000100, 0x00000100, 0x00000100,
717     0x00000100, 0x00000100, 0x00000010, 0x00000020,
718     0x00000000, 0x00000100, 0x00000000, 0x00000001,
719     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
720     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
721     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
722     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
723     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
724     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
725     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
726     0x00000008, 0x00000100, 0x00000100, 0x00000100,
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     0x00000000, 0x00000100, 0x00000100
735 };
736
737 static void test_PathIsValidCharA(void)
738 {
739     BOOL ret;
740     unsigned int c;
741
742     ret = pPathIsValidCharA( 0x7f, 0 );
743     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
744
745     ret = pPathIsValidCharA( 0x7f, 1 );
746     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
747
748     for (c = 0; c < 0x7f; c++)
749     {
750         ret = pPathIsValidCharA( c, ~0U );
751         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
752              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
753              c, (DWORD)ret, SHELL_charclass[c] );
754     }
755
756     for (c = 0x7f; c <= 0xff; c++)
757     {
758         ret = pPathIsValidCharA( c, ~0U );
759         ok ( ret == 0x00000100,
760              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x00000100\n",
761              c, (DWORD)ret );
762     }
763 }
764
765 static void test_PathIsValidCharW(void)
766 {
767     BOOL ret;
768     unsigned int c, err_count = 0;
769
770     ret = pPathIsValidCharW( 0x7f, 0 );
771     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
772
773     ret = pPathIsValidCharW( 0x7f, 1 );
774     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
775
776     for (c = 0; c < 0x7f; c++)
777     {
778         ret = pPathIsValidCharW( c, ~0U );
779         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
780              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
781              c, (DWORD)ret, SHELL_charclass[c] );
782     }
783
784     for (c = 0x007f; c <= 0xffff; c++)
785     {
786         ret = pPathIsValidCharW( c, ~0U );
787         ok ( ret == 0x00000100,
788              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x00000100\n",
789              c, (DWORD)ret );
790         if (ret != 0x00000100)
791         {
792             if(++err_count > 100 ) {
793                 trace("skipping rest of PathIsValidCharW tests "
794                       "because of the current number of errors\n");
795                 break;
796             }
797         }
798     }
799 }
800
801 static void test_PathMakePretty(void)
802 {
803    char buff[MAX_PATH];
804
805    ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
806    buff[0] = '\0';
807    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
808
809    strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
810    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
811    ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
812        "PathMakePretty: Long UC name not changed\n");
813
814    strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
815    ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
816    ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
817        "PathMakePretty: Failed but modified path\n");
818
819    strcpy(buff, "TEST");
820    ok (PathMakePrettyA(buff) == TRUE,  "PathMakePretty: Short name failed\n");
821    ok (strcmp(buff, "Test") == 0,  "PathMakePretty: 1st char lowercased %s\n", buff);
822 }
823
824 START_TEST(path)
825 {
826   hShlwapi = LoadLibraryA("shlwapi.dll");
827   if (!hShlwapi) return;
828
829   test_UrlHash();
830   test_UrlGetPart();
831   test_UrlCanonicalize();
832   test_UrlEscape();
833   test_UrlCombine();
834   test_UrlCreateFromPath();
835   test_UrlIs();
836   test_UrlUnescape();
837
838   test_PathSearchAndQualify();
839   test_PathCreateFromUrl();
840   test_PathIsUrl();
841   
842   test_PathMakePretty();
843
844   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
845    * ordinal number in some native versions. Check this to prevent a crash.
846    */
847   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
848   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
849   {
850     test_PathIsValidCharA();
851
852      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
853      if (pPathIsValidCharW) test_PathIsValidCharW();
854   }
855 }