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