Reverse the order for deleting the items in resetcontent to correctly
[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
190     {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE}
191 };
192
193 struct {
194     char *url;
195     char *path;
196     DWORD ret;
197 } TEST_PATHFROMURL[] = {
198     {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK},
199     {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK},
200     {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK},
201     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
202     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
203     {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK},
204     {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK},
205     {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK},
206     {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK},
207     {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK},
208     {"file://c:/foo/bar", "c:\\foo\\bar", S_OK},
209     {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK},
210     {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK},
211     {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK},
212     {"file:/foo/bar", "\\foo\\bar", S_OK},
213     {"file:/foo/bar/", "\\foo\\bar\\", S_OK},
214     {"file:foo/bar", "foo\\bar", S_OK},
215     {"file:c:/foo/bar", "c:\\foo\\bar", S_OK},
216     {"file:c|/foo/bar", "c:\\foo\\bar", S_OK},
217     {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK},
218     {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK},
219
220     {"c:\\foo\\bar", NULL, E_INVALIDARG},
221     {"foo/bar", NULL, E_INVALIDARG},
222     {"http://foo/bar", NULL, E_INVALIDARG},
223
224 };
225
226 struct {
227     char *url;
228     char *expect;
229 } TEST_URL_UNESCAPE[] = {
230     {"file://foo/bar", "file://foo/bar"},
231     {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"}
232 };
233
234
235 struct {
236     char *path;
237     BOOL expect;
238 } TEST_PATH_IS_URL[] = {
239     {"http://foo/bar", TRUE},
240     {"c:\\foo\\bar", FALSE},
241     {"foo://foo/bar", TRUE},
242     {"foo\\bar", FALSE},
243     {"foo.bar", FALSE}
244 };
245
246 static LPWSTR GetWideString(const char* szString)
247 {
248   LPWSTR wszString = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
249                                          (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
250   
251   MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
252
253   return wszString;
254 }
255
256 static void FreeWideString(LPWSTR wszString)
257 {
258    HeapFree(GetProcessHeap(), 0, wszString);
259 }
260
261 static void hash_url(const char* szUrl)
262 {
263   LPCSTR szTestUrl = szUrl;
264   LPWSTR wszTestUrl = GetWideString(szTestUrl);
265   
266   DWORD cbSize = sizeof(DWORD);
267   DWORD dwHash1, dwHash2;
268   ok(UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize) == S_OK, "UrlHashA didn't return S_OK\n");
269   ok(UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize) == S_OK, "UrlHashW didn't return S_OK\n");
270
271   FreeWideString(wszTestUrl);
272
273   ok(dwHash1 == dwHash2, "Hashes didn't compare\n");
274 }
275
276 static void test_UrlHash(void)
277 {
278   hash_url(TEST_URL_1);
279   hash_url(TEST_URL_2);
280   hash_url(TEST_URL_3);
281 }
282
283 static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const char* szExpected)
284 {
285   CHAR szPart[INTERNET_MAX_URL_LENGTH];
286   WCHAR wszPart[INTERNET_MAX_URL_LENGTH];
287   LPWSTR wszUrl = GetWideString(szUrl);
288   LPWSTR wszConvertedPart;
289
290   DWORD dwSize;
291
292   dwSize = INTERNET_MAX_URL_LENGTH;
293   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);
294   dwSize = INTERNET_MAX_URL_LENGTH;
295   ok( UrlGetPartW(wszUrl, wszPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartW didn't return S_OK\n" );
296
297   wszConvertedPart = GetWideString(szPart);
298
299   ok(strcmpW(wszPart,wszConvertedPart)==0, "Strings didn't match between ascii and unicode UrlGetPart!\n");
300
301   FreeWideString(wszUrl);
302   FreeWideString(wszConvertedPart);
303
304   /* Note that v6.0 and later don't return '?' with the query */
305   ok(strcmp(szPart,szExpected)==0 ||
306      (*szExpected=='?' && !strcmp(szPart,szExpected+1)),
307          "Expected %s, but got %s\n", szExpected, szPart);
308 }
309
310 static void test_UrlGetPart(void)
311 {
312   test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost");
313   test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21");
314   test_url_part(TEST_URL_3, URL_PART_USERNAME, 0, "foo");
315   test_url_part(TEST_URL_3, URL_PART_PASSWORD, 0, "bar");
316   test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http");
317   test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y");
318 }
319
320 static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
321 {
322     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
323     DWORD dwEscaped;
324     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
325     WCHAR *urlW, *expected_urlW;
326     dwEscaped=INTERNET_MAX_URL_LENGTH;
327
328     ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
329     ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
330     
331     dwEscaped = INTERNET_MAX_URL_LENGTH;
332     urlW = GetWideString(szUrl);
333     expected_urlW = GetWideString(szExpectUrl);
334     ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
335     WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
336     ok(strcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
337     FreeWideString(urlW);
338     FreeWideString(expected_urlW);
339
340 }
341
342 static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
343 {
344     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
345     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
346     LPWSTR wszUrl = GetWideString(szUrl);
347     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
348     LPWSTR wszConvertedUrl;
349     
350     DWORD dwSize;
351     
352     dwSize = INTERNET_MAX_URL_LENGTH;
353     ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08lx\n", dwExpectReturn);
354     ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
355
356     dwSize = INTERNET_MAX_URL_LENGTH;
357     ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08lx\n", dwExpectReturn);
358     wszConvertedUrl = GetWideString(szReturnUrl);
359     ok(strcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n");
360     FreeWideString(wszConvertedUrl);
361     
362             
363     FreeWideString(wszUrl);
364     FreeWideString(wszExpectUrl);
365 }
366
367
368 static void test_UrlEscape(void)
369 {
370     unsigned int i;
371     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
372         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
373                               TEST_ESCAPE[i].expectret, TEST_ESCAPE[i].expecturl);
374     }
375 }
376
377 static void test_UrlCanonicalize(void)
378 {
379     unsigned int i;
380     for(i=0; i<sizeof(TEST_CANONICALIZE)/sizeof(TEST_CANONICALIZE[0]); i++) {
381         test_url_canonicalize(TEST_CANONICALIZE[i].url, TEST_CANONICALIZE[i].flags,
382                               TEST_CANONICALIZE[i].expectret, TEST_CANONICALIZE[i].expecturl);
383     }
384 }
385
386 static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
387 {
388     HRESULT hr;
389     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
390     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
391     LPWSTR wszUrl1 = GetWideString(szUrl1);
392     LPWSTR wszUrl2 = GetWideString(szUrl2);
393     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
394     LPWSTR wszConvertedUrl;
395
396     DWORD dwSize;
397     DWORD dwExpectLen = lstrlen(szExpectUrl);
398
399     hr = UrlCombineA(szUrl1, szUrl2, NULL, NULL, dwFlags);
400     ok(hr == E_INVALIDARG, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_INVALIDARG);
401     
402     dwSize = 0;
403     hr = UrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags);
404     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
405     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
406
407     dwSize--;
408     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
409     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
410     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
411     
412     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
413     ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
414     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
415     if(SUCCEEDED(hr)) {
416         ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
417     }
418
419     dwSize = 0;
420     hr = UrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags);
421     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
422     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
423
424     dwSize--;
425     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
426     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
427     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
428     
429     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
430     ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
431     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
432     if(SUCCEEDED(hr)) {
433         wszConvertedUrl = GetWideString(szReturnUrl);
434         ok(strcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n");
435         FreeWideString(wszConvertedUrl);
436     }
437
438     FreeWideString(wszUrl1);
439     FreeWideString(wszUrl2);
440     FreeWideString(wszExpectUrl);
441 }
442
443 static void test_UrlCombine(void)
444 {
445     unsigned int i;
446     for(i=0; i<sizeof(TEST_COMBINE)/sizeof(TEST_COMBINE[0]); i++) {
447         test_url_combine(TEST_COMBINE[i].url1, TEST_COMBINE[i].url2, TEST_COMBINE[i].flags,
448                          TEST_COMBINE[i].expectret, TEST_COMBINE[i].expecturl);
449     }
450 }
451
452 static void test_UrlCreateFromPath(void)
453 {
454     int i;
455     char ret_url[INTERNET_MAX_URL_LENGTH];
456     DWORD len, ret;
457     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
458     WCHAR *pathW, *urlW;
459
460     for(i = 0; i < sizeof(TEST_URLFROMPATH) / sizeof(TEST_URLFROMPATH[0]); i++) {
461         len = INTERNET_MAX_URL_LENGTH;
462         ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
463         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path %s\n", ret, TEST_URLFROMPATH[i].path);
464         ok(!lstrcmpi(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
465         ok(len == strlen(ret_url), "ret len %ld from path %s\n", len, TEST_URLFROMPATH[i].path);
466
467         len = INTERNET_MAX_URL_LENGTH;
468         pathW = GetWideString(TEST_URLFROMPATH[i].path);
469         urlW = GetWideString(TEST_URLFROMPATH[i].url);
470         ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
471         WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
472         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path L\"%s\"\n", ret, TEST_URLFROMPATH[i].path);
473         ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n", ret_url, TEST_URLFROMPATH[i].url, TEST_URLFROMPATH[i].path);
474         ok(len == strlenW(ret_urlW), "ret len %ld from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
475         FreeWideString(urlW);
476         FreeWideString(pathW);
477     }
478 }
479
480 static void test_UrlIs(void)
481 {
482     BOOL ret;
483     INT i;
484
485     for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
486         ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL );
487         ok( ret == TEST_PATH_IS_URL[i].expect,
488             "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
489             TEST_PATH_IS_URL[i].expect );
490     }
491 }
492
493 static void test_UrlUnescape(void)
494 {
495     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
496     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
497     WCHAR *urlW, *expected_urlW; 
498     DWORD dwEscaped;
499     unsigned int i;
500
501     for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) { 
502         dwEscaped=INTERNET_MAX_URL_LENGTH;
503         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);
504         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);
505
506         dwEscaped = INTERNET_MAX_URL_LENGTH;
507         urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
508         expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
509         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);
510         WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
511         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);
512         FreeWideString(urlW);
513         FreeWideString(expected_urlW);
514     }
515
516 }
517
518 static void test_PathSearchAndQualify(void)
519 {
520     WCHAR path1[] = {'c',':','\\','f','o','o',0};
521     WCHAR expect1[] = {'c',':','\\','f','o','o',0};
522     WCHAR path2[] = {'c',':','f','o','o',0};
523     WCHAR c_drive[] = {'c',':',0}; 
524     WCHAR foo[] = {'f','o','o',0}; 
525     WCHAR path3[] = {'\\','f','o','o',0};
526     WCHAR winini[] = {'w','i','n','.','i','n','i',0};
527     WCHAR out[MAX_PATH];
528     WCHAR cur_dir[MAX_PATH];
529     WCHAR dot[] = {'.',0};
530
531     /* c:\foo */
532     ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
533        "PathSearchAndQualify rets 0\n");
534     ok(!lstrcmpiW(out, expect1), "strings don't match\n");
535
536     /* c:foo */
537     ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
538        "PathSearchAndQualify rets 0\n");
539     GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
540     PathAddBackslashW(cur_dir);
541     strcatW(cur_dir, foo);
542     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
543
544     /* foo */
545     ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
546        "PathSearchAndQualify rets 0\n");
547     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
548     PathAddBackslashW(cur_dir);
549     strcatW(cur_dir, foo);
550     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
551
552     /* \foo */
553     ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
554        "PathSearchAndQualify rets 0\n");
555     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
556     strcpyW(cur_dir + 2, path3);
557     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
558
559     /* win.ini */
560     ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
561        "PathSearchAndQualify rets 0\n");
562     if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
563         GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
564     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
565
566 }
567
568 static void test_PathCreateFromUrl(void)
569 {
570     int i;
571     char ret_path[INTERNET_MAX_URL_LENGTH];
572     DWORD len, ret;
573     WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
574     WCHAR *pathW, *urlW;
575
576     for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
577         len = INTERNET_MAX_URL_LENGTH;
578         ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
579         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url %s\n", ret, TEST_PATHFROMURL[i].url);
580         if(TEST_PATHFROMURL[i].path) {
581            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);
582            ok(len == strlen(ret_path), "ret len %ld from url %s\n", len, TEST_PATHFROMURL[i].url);
583         }
584         len = INTERNET_MAX_URL_LENGTH;
585         pathW = GetWideString(TEST_PATHFROMURL[i].path);
586         urlW = GetWideString(TEST_PATHFROMURL[i].url);
587         ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
588         WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
589         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
590         if(TEST_PATHFROMURL[i].path) {
591             ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
592             ok(len == strlenW(ret_pathW), "ret len %ld from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
593         }
594         FreeWideString(urlW);
595         FreeWideString(pathW);
596     }
597 }
598
599
600 static void test_PathIsUrl(void)
601 {
602     int i;
603     BOOL ret;
604
605     for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
606         ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
607         ok(ret == TEST_PATH_IS_URL[i].expect,
608            "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
609            TEST_PATH_IS_URL[i].expect);
610     }
611 }
612
613 static const DWORD SHELL_charclass[] =
614 {
615     0x00000000, 0x00000000, 0x00000000, 0x00000000,
616     0x00000000, 0x00000000, 0x00000000, 0x00000000,
617     0x00000000, 0x00000000, 0x00000000, 0x00000000,
618     0x00000000, 0x00000000, 0x00000000, 0x00000000,
619     0x00000000, 0x00000000, 0x00000000, 0x00000000,
620     0x00000000, 0x00000000, 0x00000000, 0x00000000,
621     0x00000000, 0x00000000, 0x00000000, 0x00000000,
622     0x00000000, 0x00000000, 0x00000000, 0x00000000,
623     0x00000080, 0x00000100, 0x00000200, 0x00000100,
624     0x00000100, 0x00000100, 0x00000100, 0x00000100,
625     0x00000100, 0x00000100, 0x00000002, 0x00000100,
626     0x00000040, 0x00000100, 0x00000004, 0x00000000,
627     0x00000100, 0x00000100, 0x00000100, 0x00000100,
628     0x00000100, 0x00000100, 0x00000100, 0x00000100,
629     0x00000100, 0x00000100, 0x00000010, 0x00000020,
630     0x00000000, 0x00000100, 0x00000000, 0x00000001,
631     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
632     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
633     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
634     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
635     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
636     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
637     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
638     0x00000008, 0x00000100, 0x00000100, 0x00000100,
639     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
640     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
641     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
642     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
643     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
644     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
645     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
646     0x00000000, 0x00000100, 0x00000100
647 };
648
649 static void test_PathIsValidCharA(void)
650 {
651     BOOL ret;
652     unsigned int c;
653
654     ret = pPathIsValidCharA( 0x7f, 0 );
655     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
656
657     ret = pPathIsValidCharA( 0x7f, 1 );
658     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
659
660     for (c = 0; c < 0x7f; c++)
661     {
662         ret = pPathIsValidCharA( c, ~0U );
663         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
664              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
665              c, (DWORD)ret, SHELL_charclass[c] );
666     }
667
668     for (c = 0x7f; c <= 0xff; c++)
669     {
670         ret = pPathIsValidCharA( c, ~0U );
671         ok ( ret == 0x00000100,
672              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x00000100\n",
673              c, (DWORD)ret );
674     }
675 }
676
677 static void test_PathIsValidCharW(void)
678 {
679     BOOL ret;
680     unsigned int c;
681
682     ret = pPathIsValidCharW( 0x7f, 0 );
683     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
684
685     ret = pPathIsValidCharW( 0x7f, 1 );
686     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
687
688     for (c = 0; c < 0x7f; c++)
689     {
690         ret = pPathIsValidCharW( c, ~0U );
691         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
692              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
693              c, (DWORD)ret, SHELL_charclass[c] );
694     }
695
696     for (c = 0x007f; c <= 0xffff; c++)
697     {
698         ret = pPathIsValidCharW( c, ~0U );
699         ok ( ret == 0x00000100,
700              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x00000100\n",
701              c, (DWORD)ret );
702     }
703 }
704
705 START_TEST(path)
706 {
707   hShlwapi = LoadLibraryA("shlwapi.dll");
708   if (!hShlwapi) return;
709
710   test_UrlHash();
711   test_UrlGetPart();
712   test_UrlCanonicalize();
713   test_UrlEscape();
714   test_UrlCombine();
715   test_UrlCreateFromPath();
716   test_UrlIs();
717   test_UrlUnescape();
718
719   test_PathSearchAndQualify();
720   test_PathCreateFromUrl();
721   test_PathIsUrl();
722
723   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
724   if (pPathIsValidCharA) test_PathIsValidCharA();
725
726   pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
727   if (pPathIsValidCharW) test_PathIsValidCharW();
728 }