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