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