shlwapi: Add tests for PathCommonPrefixA.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winreg.h"
28 #include "shlwapi.h"
29 #include "wininet.h"
30
31 static HMODULE hShlwapi;
32 static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD);
33 static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD);
34 static LPWSTR  (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR);
35
36 const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
37 const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
38 const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
39
40 typedef struct _TEST_URL_CANONICALIZE {
41     const char *url;
42     DWORD flags;
43     HRESULT expectret;
44     const char *expecturl;
45 } TEST_URL_CANONICALIZE;
46
47 const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
48     /*FIXME {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/"},*/
49     {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests"},
50     {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
51     {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"},
52     {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests"},
53     {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests"},
54     {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/"},
55     {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/"},
56     {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/"},
57     {"http://www.winehq.org/tests/..", 0, S_OK, "http://www.winehq.org/"},
58     {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/"},
59     {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"},
60     {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"},
61     {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example"},
62     {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example"},
63     {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example"},
64     {"http://www.winehq.org/tests/..\\#example", 0, S_OK, "http://www.winehq.org/#example"},
65     {"http://www.winehq.org\\tests/../#example", 0, S_OK, "http://www.winehq.org/#example"},
66     {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example"},
67     {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar"},
68     {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar"},
69     {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"},
70     {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"},
71     {"file:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
72     {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
73     {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
74     {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar"},
75     {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar"},
76     {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar"},
77     {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar"},
78 };
79
80 typedef struct _TEST_URL_ESCAPE {
81     const char *url;
82     DWORD flags;
83     DWORD expectescaped;
84     HRESULT expectret;
85     const char *expecturl;
86 } TEST_URL_ESCAPE;
87
88 const TEST_URL_ESCAPE TEST_ESCAPE[] = {
89     {"http://www.winehq.org/tests0", 0, 0, S_OK, "http://www.winehq.org/tests0"},
90     {"http://www.winehq.org/tests1\n", 0, 0, S_OK, "http://www.winehq.org/tests1%0A"},
91     {"http://www.winehq.org/tests2\r", 0, 0, S_OK, "http://www.winehq.org/tests2%0D"},
92     {"http://www.winehq.org/tests3\r", URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, 0, S_OK, "http://www.winehq.org/tests3\r"},
93     {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"},
94     {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"},
95     {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
96
97     {"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
98     {"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
99     {"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
100     {"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
101     {"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
102     {"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
103     {"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
104     {"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"},
105     {"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
106     {"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"},
107     {"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
108     {"file:\\\\foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"},
109     {"file:\\\\\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
110     {"file:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"},
111     {"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"},
112     {"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"},
113     {"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, 0, S_OK, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"},
114     {"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"},
115     {"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"},
116
117     {"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"},
118     {"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"},
119     {"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"},
120     {"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"},
121     {"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"},
122     {"/foo/%5C", 0, 0, S_OK, "/foo/%5C"},
123     {"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"},
124
125     {"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"},
126     {"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"},
127     {"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
128     {"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
129     {"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"},
130     {"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
131     {"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
132     {"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"},
133     {"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"},
134     {"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"},
135     {"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"},
136     {"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"},
137     {"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"},
138     {"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"},
139     {"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"},
140     {"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"},
141
142     {"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"},
143     {"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
144     {"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"},
145
146     {"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"},
147     {"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"},
148     {"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"},
149     {"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"},
150     {"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"},
151     {"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"},
152     {"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"},
153     {"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"},
154     {"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"},
155
156     {"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
157     {"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
158     {"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, 0, S_OK, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"},
159
160     {"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
161     {"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"},
162     {"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"},
163     {"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"},
164     {"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"},
165     {"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"},
166     {"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"}
167 };
168
169 typedef struct _TEST_URL_COMBINE {
170     const char *url1;
171     const char *url2;
172     DWORD flags;
173     HRESULT expectret;
174     const char *expecturl;
175 } TEST_URL_COMBINE;
176
177 const TEST_URL_COMBINE TEST_COMBINE[] = {
178     {"http://www.winehq.org/tests", "tests1", 0, S_OK, "http://www.winehq.org/tests1"},
179     {"http://www.%77inehq.org/tests", "tests1", 0, S_OK, "http://www.%77inehq.org/tests1"},
180     /*FIXME {"http://www.winehq.org/tests", "../tests2", 0, S_OK, "http://www.winehq.org/tests2"},*/
181     {"http://www.winehq.org/tests/", "../tests3", 0, S_OK, "http://www.winehq.org/tests3"},
182     {"http://www.winehq.org/tests/test1", "test2", 0, S_OK, "http://www.winehq.org/tests/test2"},
183     {"http://www.winehq.org/tests/../tests", "tests4", 0, S_OK, "http://www.winehq.org/tests4"},
184     {"http://www.winehq.org/tests/../tests/", "tests5", 0, S_OK, "http://www.winehq.org/tests/tests5"},
185     {"http://www.winehq.org/tests/../tests/", "/tests6/..", 0, S_OK, "http://www.winehq.org/"},
186     {"http://www.winehq.org/tests/../tests/..", "tests7/..", 0, S_OK, "http://www.winehq.org/"},
187     {"http://www.winehq.org/tests/?query=x&return=y", "tests8", 0, S_OK, "http://www.winehq.org/tests/tests8"},
188     {"http://www.winehq.org/tests/#example", "tests9", 0, S_OK, "http://www.winehq.org/tests/tests9"},
189     {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."},
190     {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"},
191     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}
192 };
193
194 struct {
195     const char *path;
196     const char *url;
197     DWORD ret;
198 } TEST_URLFROMPATH [] = {
199     {"foo", "file:foo", S_OK},
200     {"foo\\bar", "file:foo/bar", S_OK},
201     {"\\foo\\bar", "file:///foo/bar", S_OK},
202     {"c:\\foo\\bar", "file:///c:/foo/bar", S_OK},
203     {"c:foo\\bar", "file:///c:foo/bar", S_OK},
204     {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK},
205     {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK},
206 #if 0
207     /* The following test fails on native shlwapi as distributed with Win95/98.
208      * Wine matches the behaviour of later versions.
209      */
210     {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE}
211 #endif
212 };
213
214 struct {
215     const char *url;
216     const char *path;
217     DWORD ret;
218 } TEST_PATHFROMURL[] = {
219     {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK},
220     {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK},
221     {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK},
222     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
223     {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK},
224     {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK},
225     {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK},
226     {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK},
227     {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK},
228     {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK},
229     {"file://c:/foo/bar", "c:\\foo\\bar", S_OK},
230     {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK},
231     {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK},
232     {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK},
233     {"file:/foo/bar", "\\foo\\bar", S_OK},
234     {"file:/foo/bar/", "\\foo\\bar\\", S_OK},
235     {"file:foo/bar", "foo\\bar", S_OK},
236     {"file:c:/foo/bar", "c:\\foo\\bar", S_OK},
237     {"file:c|/foo/bar", "c:\\foo\\bar", S_OK},
238     {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK},
239     {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK},
240 /*    {"file:////c:/foo/foo%20bar", "c:\\foo\\foo%20bar", S_OK},*/
241
242     {"c:\\foo\\bar", NULL, E_INVALIDARG},
243     {"foo/bar", NULL, E_INVALIDARG},
244     {"http://foo/bar", NULL, E_INVALIDARG},
245
246 };
247
248 struct {
249     char url[30];
250     const char *expect;
251 } TEST_URL_UNESCAPE[] = {
252     {"file://foo/bar", "file://foo/bar"},
253     {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"}
254 };
255
256
257 struct {
258     const char *path;
259     BOOL expect;
260 } TEST_PATH_IS_URL[] = {
261     {"http://foo/bar", TRUE},
262     {"c:\\foo\\bar", FALSE},
263     {"foo://foo/bar", TRUE},
264     {"foo\\bar", FALSE},
265     {"foo.bar", FALSE},
266     {"bogusscheme:", TRUE},
267     {"http:partial", TRUE}
268 };
269
270 struct {
271     const char *url;
272     BOOL expectOpaque;
273     BOOL expectFile;
274 } TEST_URLIS_ATTRIBS[] = {
275     {   "ftp:",                                         FALSE,  FALSE   },
276     {   "http:",                                        FALSE,  FALSE   },
277     {   "gopher:",                                      FALSE,  FALSE   },
278     {   "mailto:",                                      TRUE,   FALSE   },
279     {   "news:",                                        FALSE,  FALSE   },
280     {   "nntp:",                                        FALSE,  FALSE   },
281     {   "telnet:",                                      FALSE,  FALSE   },
282     {   "wais:",                                        FALSE,  FALSE   },
283     {   "file:",                                        FALSE,  TRUE    },
284     {   "mk:",                                          FALSE,  FALSE   },
285     {   "https:",                                       FALSE,  FALSE   },
286     {   "shell:",                                       TRUE,   FALSE   },
287     {   "https:",                                       FALSE,  FALSE   },
288     {   "snews:",                                       FALSE,  FALSE   },
289     {   "local:",                                       FALSE,  FALSE   },
290     {   "javascript:",                                  TRUE,   FALSE   },
291     {   "vbscript:",                                    TRUE,   FALSE   },
292     {   "about:",                                       TRUE,   FALSE   },
293     {   "res:",                                         FALSE,  FALSE   },
294     {   "bogusscheme:",                                 FALSE,  FALSE   },
295     {   "file:\\\\e:\\b\\c",                            FALSE,  TRUE    },
296     {   "file://e:/b/c",                                FALSE,  TRUE    },
297     {   "http:partial",                                 FALSE,  FALSE   },
298     {   "mailto://www.winehq.org/test.html",            TRUE,   FALSE   },
299     {   "file:partial",                                 FALSE,  TRUE    }
300 };
301
302
303 static LPWSTR GetWideString(const char* szString)
304 {
305   LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
306   
307   MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
308
309   return wszString;
310 }
311
312 static void FreeWideString(LPWSTR wszString)
313 {
314    HeapFree(GetProcessHeap(), 0, wszString);
315 }
316
317 static void hash_url(const char* szUrl)
318 {
319   LPCSTR szTestUrl = szUrl;
320   LPWSTR wszTestUrl = GetWideString(szTestUrl);
321   
322   DWORD cbSize = sizeof(DWORD);
323   DWORD dwHash1, dwHash2;
324   ok(UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize) == S_OK, "UrlHashA didn't return S_OK\n");
325   ok(UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize) == S_OK, "UrlHashW didn't return S_OK\n");
326
327   FreeWideString(wszTestUrl);
328
329   ok(dwHash1 == dwHash2, "Hashes didn't compare\n");
330 }
331
332 static void test_UrlHash(void)
333 {
334   hash_url(TEST_URL_1);
335   hash_url(TEST_URL_2);
336   hash_url(TEST_URL_3);
337 }
338
339 static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const char* szExpected)
340 {
341   CHAR szPart[INTERNET_MAX_URL_LENGTH];
342   WCHAR wszPart[INTERNET_MAX_URL_LENGTH];
343   LPWSTR wszUrl = GetWideString(szUrl);
344   LPWSTR wszConvertedPart;
345
346   DWORD dwSize;
347
348   dwSize = INTERNET_MAX_URL_LENGTH;
349   ok( UrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartA for \"%s\" part 0x%08lx didn't return S_OK but \"%s\"\n", szUrl, dwPart, szPart);
350   dwSize = INTERNET_MAX_URL_LENGTH;
351   ok( UrlGetPartW(wszUrl, wszPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartW didn't return S_OK\n" );
352
353   wszConvertedPart = GetWideString(szPart);
354
355   ok(lstrcmpW(wszPart,wszConvertedPart)==0, "Strings didn't match between ascii and unicode UrlGetPart!\n");
356
357   FreeWideString(wszUrl);
358   FreeWideString(wszConvertedPart);
359
360   /* Note that v6.0 and later don't return '?' with the query */
361   ok(strcmp(szPart,szExpected)==0 ||
362      (*szExpected=='?' && !strcmp(szPart,szExpected+1)),
363          "Expected %s, but got %s\n", szExpected, szPart);
364 }
365
366 static void test_UrlGetPart(void)
367 {
368   CHAR szPart[INTERNET_MAX_URL_LENGTH];
369   DWORD dwSize;
370   HRESULT res;
371
372   dwSize = sizeof szPart;
373   szPart[0]='x'; szPart[1]=0;
374   res = UrlGetPartA("hi", szPart, &dwSize, URL_PART_SCHEME, 0);
375   todo_wine {
376   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08lX\n", res);
377   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
378   }
379   dwSize = sizeof szPart;
380   szPart[0]='x'; szPart[1]=0;
381   res = UrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0);
382   todo_wine {
383   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08lX\n", res);
384   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
385   }
386   
387   test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost");
388   test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21");
389   test_url_part(TEST_URL_3, URL_PART_USERNAME, 0, "foo");
390   test_url_part(TEST_URL_3, URL_PART_PASSWORD, 0, "bar");
391   test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http");
392   test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y");
393 }
394
395 static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
396 {
397     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
398     DWORD dwEscaped;
399     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
400     WCHAR *urlW, *expected_urlW;
401     dwEscaped=INTERNET_MAX_URL_LENGTH;
402
403     ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
404     ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl);
405     
406     dwEscaped = INTERNET_MAX_URL_LENGTH;
407     urlW = GetWideString(szUrl);
408     expected_urlW = GetWideString(szExpectUrl);
409     ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl);
410     WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
411     ok(lstrcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags);
412     FreeWideString(urlW);
413     FreeWideString(expected_urlW);
414
415 }
416
417 static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
418 {
419     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
420     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
421     LPWSTR wszUrl = GetWideString(szUrl);
422     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
423     LPWSTR wszConvertedUrl;
424     
425     DWORD dwSize;
426     
427     dwSize = INTERNET_MAX_URL_LENGTH;
428     ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
429     ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08lx\n", dwExpectReturn);
430     ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08lx Expected %s, but got %s\n", dwFlags, szExpectUrl, szReturnUrl);
431
432     dwSize = INTERNET_MAX_URL_LENGTH;
433     ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n");
434     ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08lx\n", dwExpectReturn);
435     wszConvertedUrl = GetWideString(szReturnUrl);
436     ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n");
437     FreeWideString(wszConvertedUrl);
438     
439             
440     FreeWideString(wszUrl);
441     FreeWideString(wszExpectUrl);
442 }
443
444
445 static void test_UrlEscape(void)
446 {
447     unsigned int i;
448     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
449         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
450                               TEST_ESCAPE[i].expectret, TEST_ESCAPE[i].expecturl);
451     }
452 }
453
454 static void test_UrlCanonicalize(void)
455 {
456     unsigned int i;
457     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
458     DWORD dwSize;
459
460     for(i=0; i<sizeof(TEST_CANONICALIZE)/sizeof(TEST_CANONICALIZE[0]); i++) {
461         test_url_canonicalize(TEST_CANONICALIZE[i].url, TEST_CANONICALIZE[i].flags,
462                               TEST_CANONICALIZE[i].expectret, TEST_CANONICALIZE[i].expecturl);
463     }
464
465     /* move to TEST_CANONICALIZE when fixed */
466     dwSize = sizeof szReturnUrl;
467     ok(UrlCanonicalizeA("c:\\tests\\foo bar", szReturnUrl, &dwSize, 0) == S_OK, "UrlCanonicalizeA didn't return 0x%08lx\n", S_OK);
468     todo_wine {
469         ok(strcmp(szReturnUrl,"file:///c:/tests/foo%20bar")==0, "UrlCanonicalizeA got %s\n", szReturnUrl);
470     }
471 }
472
473 static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
474 {
475     HRESULT hr;
476     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
477     WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
478     LPWSTR wszUrl1 = GetWideString(szUrl1);
479     LPWSTR wszUrl2 = GetWideString(szUrl2);
480     LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
481     LPWSTR wszConvertedUrl;
482
483     DWORD dwSize;
484     DWORD dwExpectLen = lstrlen(szExpectUrl);
485
486     hr = UrlCombineA(szUrl1, szUrl2, NULL, NULL, dwFlags);
487     ok(hr == E_INVALIDARG, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_INVALIDARG);
488     
489     dwSize = 0;
490     hr = UrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags);
491     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
492     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
493
494     dwSize--;
495     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
496     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
497     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
498     
499     hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
500     ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
501     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
502     if(SUCCEEDED(hr)) {
503         ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
504     }
505
506     dwSize = 0;
507     hr = UrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags);
508     ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
509     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
510
511     dwSize--;
512     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
513     ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
514     ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
515     
516     hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
517     ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
518     ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
519     if(SUCCEEDED(hr)) {
520         wszConvertedUrl = GetWideString(szReturnUrl);
521         ok(lstrcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n");
522         FreeWideString(wszConvertedUrl);
523     }
524
525     FreeWideString(wszUrl1);
526     FreeWideString(wszUrl2);
527     FreeWideString(wszExpectUrl);
528 }
529
530 static void test_UrlCombine(void)
531 {
532     unsigned int i;
533     for(i=0; i<sizeof(TEST_COMBINE)/sizeof(TEST_COMBINE[0]); i++) {
534         test_url_combine(TEST_COMBINE[i].url1, TEST_COMBINE[i].url2, TEST_COMBINE[i].flags,
535                          TEST_COMBINE[i].expectret, TEST_COMBINE[i].expecturl);
536     }
537 }
538
539 static void test_UrlCreateFromPath(void)
540 {
541     size_t i;
542     char ret_url[INTERNET_MAX_URL_LENGTH];
543     DWORD len, ret;
544     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
545     WCHAR *pathW, *urlW;
546
547     for(i = 0; i < sizeof(TEST_URLFROMPATH) / sizeof(TEST_URLFROMPATH[0]); i++) {
548         len = INTERNET_MAX_URL_LENGTH;
549         ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
550         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path %s\n", ret, TEST_URLFROMPATH[i].path);
551         ok(!lstrcmpi(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
552         ok(len == strlen(ret_url), "ret len %ld from path %s\n", len, TEST_URLFROMPATH[i].path);
553
554         len = INTERNET_MAX_URL_LENGTH;
555         pathW = GetWideString(TEST_URLFROMPATH[i].path);
556         urlW = GetWideString(TEST_URLFROMPATH[i].url);
557         ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
558         WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
559         ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path L\"%s\", expected %08lx\n",
560            ret, TEST_URLFROMPATH[i].path, TEST_URLFROMPATH[i].ret);
561         ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n", ret_url, TEST_URLFROMPATH[i].url, TEST_URLFROMPATH[i].path);
562         ok(len == lstrlenW(ret_urlW), "ret len %ld from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
563         FreeWideString(urlW);
564         FreeWideString(pathW);
565     }
566 }
567
568 static void test_UrlIs(void)
569 {
570     BOOL ret;
571     size_t i;
572     WCHAR wurl[80];
573
574     for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
575         MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80);
576
577         ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL );
578         ok( ret == TEST_PATH_IS_URL[i].expect,
579             "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
580             TEST_PATH_IS_URL[i].expect );
581
582         ret = UrlIsW( wurl, URLIS_URL );
583         ok( ret == TEST_PATH_IS_URL[i].expect,
584             "returned %d from path (UrlIsW) %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
585             TEST_PATH_IS_URL[i].expect );
586     }
587     for(i = 0; i < sizeof(TEST_URLIS_ATTRIBS) / sizeof(TEST_URLIS_ATTRIBS[0]); i++) {
588         MultiByteToWideChar(CP_ACP, 0, TEST_URLIS_ATTRIBS[i].url, -1, wurl, 80);
589
590         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_OPAQUE);
591         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
592             "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
593             TEST_URLIS_ATTRIBS[i].expectOpaque );
594         ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_FILEURL);
595         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
596             "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
597             TEST_URLIS_ATTRIBS[i].expectFile );
598
599         ret = UrlIsW( wurl, URLIS_OPAQUE);
600         ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
601             "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
602             TEST_URLIS_ATTRIBS[i].expectOpaque );
603         ret = UrlIsW( wurl, URLIS_FILEURL);
604         ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
605             "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
606             TEST_URLIS_ATTRIBS[i].expectFile );
607     }
608 }
609
610 static void test_UrlUnescape(void)
611 {
612     CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
613     WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
614     WCHAR *urlW, *expected_urlW; 
615     DWORD dwEscaped;
616     size_t i;
617     static char inplace[] = "file:///C:/Program%20Files";
618     static WCHAR inplaceW[] = {'f','i','l','e',':','/','/','/','C',':','/',
619                                'P','r','o','g','r','a','m','%','2','0','F','i','l','e','s',0};
620
621     for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) { 
622         dwEscaped=INTERNET_MAX_URL_LENGTH;
623         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);
624         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);
625
626         dwEscaped = INTERNET_MAX_URL_LENGTH;
627         urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
628         expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
629         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);
630         WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0);
631         ok(lstrcmpW(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);
632         FreeWideString(urlW);
633         FreeWideString(expected_urlW);
634     }
635
636     dwEscaped = sizeof(inplace);
637     ok(UrlUnescapeA(inplace, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeA failed unexpectedly\n");
638
639     dwEscaped = sizeof(inplaceW);
640     ok(UrlUnescapeW(inplaceW, NULL, &dwEscaped, URL_UNESCAPE_INPLACE) == S_OK, "UrlUnescapeW failed unexpectedly\n");
641 }
642
643 static void test_PathSearchAndQualify(void)
644 {
645     WCHAR path1[] = {'c',':','\\','f','o','o',0};
646     WCHAR expect1[] = {'c',':','\\','f','o','o',0};
647     WCHAR path2[] = {'c',':','f','o','o',0};
648     WCHAR c_drive[] = {'c',':',0}; 
649     WCHAR foo[] = {'f','o','o',0}; 
650     WCHAR path3[] = {'\\','f','o','o',0};
651     WCHAR winini[] = {'w','i','n','.','i','n','i',0};
652     WCHAR out[MAX_PATH];
653     WCHAR cur_dir[MAX_PATH];
654     WCHAR dot[] = {'.',0};
655
656     /* c:\foo */
657     ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
658        "PathSearchAndQualify rets 0\n");
659     ok(!lstrcmpiW(out, expect1), "strings don't match\n");
660
661     /* c:foo */
662     ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
663        "PathSearchAndQualify rets 0\n");
664     GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
665     PathAddBackslashW(cur_dir);
666     lstrcatW(cur_dir, foo);
667     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
668
669     /* foo */
670     ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
671        "PathSearchAndQualify rets 0\n");
672     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
673     PathAddBackslashW(cur_dir);
674     lstrcatW(cur_dir, foo);
675     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");    
676
677     /* \foo */
678     ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
679        "PathSearchAndQualify rets 0\n");
680     GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
681     lstrcpyW(cur_dir + 2, path3);
682     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
683
684     /* win.ini */
685     ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
686        "PathSearchAndQualify rets 0\n");
687     if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
688         GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
689     ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
690
691 }
692
693 static void test_PathCreateFromUrl(void)
694 {
695     size_t i;
696     char ret_path[INTERNET_MAX_URL_LENGTH];
697     DWORD len, ret;
698     WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
699     WCHAR *pathW, *urlW;
700
701     for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
702         len = INTERNET_MAX_URL_LENGTH;
703         ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
704         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url %s\n", ret, TEST_PATHFROMURL[i].url);
705         if(TEST_PATHFROMURL[i].path) {
706            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);
707            ok(len == strlen(ret_path), "ret len %ld from url %s\n", len, TEST_PATHFROMURL[i].url);
708         }
709         len = INTERNET_MAX_URL_LENGTH;
710         pathW = GetWideString(TEST_PATHFROMURL[i].path);
711         urlW = GetWideString(TEST_PATHFROMURL[i].url);
712         ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
713         WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
714         ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
715         if(TEST_PATHFROMURL[i].path) {
716             ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
717             ok(len == lstrlenW(ret_pathW), "ret len %ld from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
718         }
719         FreeWideString(urlW);
720         FreeWideString(pathW);
721     }
722 }
723
724
725 static void test_PathIsUrl(void)
726 {
727     size_t i;
728     BOOL ret;
729
730     for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
731         ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
732         ok(ret == TEST_PATH_IS_URL[i].expect,
733            "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
734            TEST_PATH_IS_URL[i].expect);
735     }
736 }
737
738 static const DWORD SHELL_charclass[] =
739 {
740     0x00000000, 0x00000000, 0x00000000, 0x00000000,
741     0x00000000, 0x00000000, 0x00000000, 0x00000000,
742     0x00000000, 0x00000000, 0x00000000, 0x00000000,
743     0x00000000, 0x00000000, 0x00000000, 0x00000000,
744     0x00000000, 0x00000000, 0x00000000, 0x00000000,
745     0x00000000, 0x00000000, 0x00000000, 0x00000000,
746     0x00000000, 0x00000000, 0x00000000, 0x00000000,
747     0x00000000, 0x00000000, 0x00000000, 0x00000000,
748     0x00000080, 0x00000100, 0x00000200, 0x00000100,
749     0x00000100, 0x00000100, 0x00000100, 0x00000100,
750     0x00000100, 0x00000100, 0x00000002, 0x00000100,
751     0x00000040, 0x00000100, 0x00000004, 0x00000000,
752     0x00000100, 0x00000100, 0x00000100, 0x00000100,
753     0x00000100, 0x00000100, 0x00000100, 0x00000100,
754     0x00000100, 0x00000100, 0x00000010, 0x00000020,
755     0x00000000, 0x00000100, 0x00000000, 0x00000001,
756     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
757     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
758     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
759     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
760     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
761     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
762     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
763     0x00000008, 0x00000100, 0x00000100, 0x00000100,
764     0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
765     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
766     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
767     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
768     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
769     0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
770     0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
771     0x00000000, 0x00000100, 0x00000100
772 };
773
774 static void test_PathIsValidCharA(void)
775 {
776     BOOL ret;
777     unsigned int c;
778
779     ret = pPathIsValidCharA( 0x7f, 0 );
780     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
781
782     ret = pPathIsValidCharA( 0x7f, 1 );
783     ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
784
785     for (c = 0; c < 0x7f; c++)
786     {
787         ret = pPathIsValidCharA( c, ~0U );
788         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
789              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
790              c, (DWORD)ret, SHELL_charclass[c] );
791     }
792
793     for (c = 0x7f; c <= 0xff; c++)
794     {
795         ret = pPathIsValidCharA( c, ~0U );
796         ok ( ret == 0x00000100,
797              "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x00000100\n",
798              c, (DWORD)ret );
799     }
800 }
801
802 static void test_PathIsValidCharW(void)
803 {
804     BOOL ret;
805     unsigned int c, err_count = 0;
806
807     ret = pPathIsValidCharW( 0x7f, 0 );
808     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
809
810     ret = pPathIsValidCharW( 0x7f, 1 );
811     ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
812
813     for (c = 0; c < 0x7f; c++)
814     {
815         ret = pPathIsValidCharW( c, ~0U );
816         ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
817              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
818              c, (DWORD)ret, SHELL_charclass[c] );
819     }
820
821     for (c = 0x007f; c <= 0xffff; c++)
822     {
823         ret = pPathIsValidCharW( c, ~0U );
824         ok ( ret == 0x00000100,
825              "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x00000100\n",
826              c, (DWORD)ret );
827         if (ret != 0x00000100)
828         {
829             if(++err_count > 100 ) {
830                 trace("skipping rest of PathIsValidCharW tests "
831                       "because of the current number of errors\n");
832                 break;
833             }
834         }
835     }
836 }
837
838 static void test_PathMakePretty(void)
839 {
840    char buff[MAX_PATH];
841
842    ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
843    buff[0] = '\0';
844    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
845
846    strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
847    ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
848    ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
849        "PathMakePretty: Long UC name not changed\n");
850
851    strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
852    ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
853    ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
854        "PathMakePretty: Failed but modified path\n");
855
856    strcpy(buff, "TEST");
857    ok (PathMakePrettyA(buff) == TRUE,  "PathMakePretty: Short name failed\n");
858    ok (strcmp(buff, "Test") == 0,  "PathMakePretty: 1st char lowercased %s\n", buff);
859 }
860
861 static void test_PathMatchSpec(void)
862 {
863     static const char file[] = "c:\\foo\\bar\\filename.ext";
864     static const char spec1[] = ".ext";
865     static const char spec2[] = "*.ext";
866     static const char spec3[] = "*.ext ";
867     static const char spec4[] = "  *.ext";
868     static const char spec5[] = "* .ext";
869     static const char spec6[] = "*. ext";
870     static const char spec7[] = "* . ext";
871     static const char spec8[] = "*.e?t";
872     static const char spec9[] = "filename.ext";
873     static const char spec10[] = "*bar\\filename.ext";
874     static const char spec11[] = " foo; *.ext";
875     static const char spec12[] = "*.ext;*.bar";
876     static const char spec13[] = "*bar*";
877
878     ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
879     ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
880     ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
881     ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
882     todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
883     todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
884     ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
885     ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
886     ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
887     ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
888     ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
889     ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
890     ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
891 }
892
893 static void test_PathCombineW(void)
894 {
895     LPWSTR wszString, wszString2;
896    
897     wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
898
899     /* NULL test */
900     wszString = pPathCombineW(NULL, NULL, NULL);
901     ok (wszString == NULL, "Expected a NULL return\n");
902
903     /* Some NULL */
904     wszString = pPathCombineW(wszString2, NULL, NULL);
905     ok (wszString == NULL, "Expected a NULL return\n");
906  
907     HeapFree(GetProcessHeap(), 0, wszString2);
908 }
909
910 #define LONG_LEN (MAX_PATH * 2)
911 #define HALF_LEN (MAX_PATH / 2 + 1)
912
913 static void test_PathCombineA(void)
914 {
915     LPSTR str;
916     char dest[MAX_PATH];
917     char too_long[LONG_LEN];
918     char one[HALF_LEN], two[HALF_LEN];
919
920     /* try NULL dest */
921     SetLastError(0xdeadbeef);
922     str = PathCombineA(NULL, "C:\\", "one\\two\\three");
923     ok(str == NULL, "Expected NULL, got %p\n", str);
924     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
925
926     /* try NULL dest and NULL directory */
927     SetLastError(0xdeadbeef);
928     str = PathCombineA(NULL, NULL, "one\\two\\three");
929     ok(str == NULL, "Expected NULL, got %p\n", str);
930     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
931
932     /* try all NULL*/
933     SetLastError(0xdeadbeef);
934     str = PathCombineA(NULL, NULL, NULL);
935     ok(str == NULL, "Expected NULL, got %p\n", str);
936     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
937
938     /* try NULL file part */
939     SetLastError(0xdeadbeef);
940     lstrcpyA(dest, "control");
941     str = PathCombineA(dest, "C:\\", NULL);
942     ok(str == dest, "Expected str == dest, got %p\n", str);
943     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
944     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
945
946     /* try empty file part */
947     SetLastError(0xdeadbeef);
948     lstrcpyA(dest, "control");
949     str = PathCombineA(dest, "C:\\", "");
950     ok(str == dest, "Expected str == dest, got %p\n", str);
951     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
952     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
953
954     /* try empty directory and file part */
955     SetLastError(0xdeadbeef);
956     lstrcpyA(dest, "control");
957     str = PathCombineA(dest, "", "");
958     ok(str == dest, "Expected str == dest, got %p\n", str);
959     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
960     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
961
962     /* try NULL directory */
963     SetLastError(0xdeadbeef);
964     lstrcpyA(dest, "control");
965     str = PathCombineA(dest, NULL, "one\\two\\three");
966     ok(str == dest, "Expected str == dest, got %p\n", str);
967     ok(!lstrcmp(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
968     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
969
970     /* try NULL directory and empty file part */
971     SetLastError(0xdeadbeef);
972     lstrcpyA(dest, "control");
973     str = PathCombineA(dest, NULL, "");
974     ok(str == dest, "Expected str == dest, got %p\n", str);
975     ok(!lstrcmp(str, "\\"), "Expected \\, got %s\n", str);
976     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
977
978     /* try NULL directory and file part */
979     SetLastError(0xdeadbeef);
980     lstrcpyA(dest, "control");
981     str = PathCombineA(dest, NULL, NULL);
982     ok(str == NULL, "Expected str == NULL, got %p\n", str);
983     todo_wine
984     {
985         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
986     }
987     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
988
989     /* try directory without backslash */
990     SetLastError(0xdeadbeef);
991     lstrcpyA(dest, "control");
992     str = PathCombineA(dest, "C:", "one\\two\\three");
993     ok(str == dest, "Expected str == dest, got %p\n", str);
994     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
995     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
996
997     /* try directory with backslash */
998     SetLastError(0xdeadbeef);
999     lstrcpyA(dest, "control");
1000     str = PathCombineA(dest, "C:\\", "one\\two\\three");
1001     ok(str == dest, "Expected str == dest, got %p\n", str);
1002     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1003     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1004
1005     /* try directory with backslash and file with prepended backslash */
1006     SetLastError(0xdeadbeef);
1007     lstrcpyA(dest, "control");
1008     str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
1009     ok(str == dest, "Expected str == dest, got %p\n", str);
1010     ok(!lstrcmp(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
1011     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1012
1013     /* try previous test, with backslash appended as well */
1014     SetLastError(0xdeadbeef);
1015     lstrcpyA(dest, "control");
1016     str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
1017     ok(str == dest, "Expected str == dest, got %p\n", str);
1018     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1019     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1020
1021     /* try a relative directory */
1022     SetLastError(0xdeadbeef);
1023     lstrcpyA(dest, "control");
1024     str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
1025     ok(str == dest, "Expected str == dest, got %p\n", str);
1026     ok(!lstrcmp(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
1027     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1028
1029     /* try forward slashes */
1030     SetLastError(0xdeadbeef);
1031     lstrcpyA(dest, "control");
1032     str = PathCombineA(dest, "C:\\", "one/two/three\\");
1033     ok(str == dest, "Expected str == dest, got %p\n", str);
1034     ok(!lstrcmp(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
1035     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1036
1037     /* try a really weird directory */
1038     SetLastError(0xdeadbeef);
1039     lstrcpyA(dest, "control");
1040     str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
1041     ok(str == dest, "Expected str == dest, got %p\n", str);
1042     ok(!lstrcmp(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
1043     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1044
1045     /* try periods */
1046     SetLastError(0xdeadbeef);
1047     lstrcpyA(dest, "control");
1048     str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
1049     ok(str == dest, "Expected str == dest, got %p\n", str);
1050     ok(!lstrcmp(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
1051     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1052
1053     /* try .. as file */
1054     /* try forward slashes */
1055     SetLastError(0xdeadbeef);
1056     lstrcpyA(dest, "control");
1057     str = PathCombineA(dest, "C:\\", "..");
1058     ok(str == dest, "Expected str == dest, got %p\n", str);
1059     ok(!lstrcmp(str, "C:\\"), "Expected C:\\, got %s\n", str);
1060     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1061
1062     memset(too_long, 'a', LONG_LEN);
1063     too_long[LONG_LEN - 1] = '\0';
1064
1065     /* try a file longer than MAX_PATH */
1066     SetLastError(0xdeadbeef);
1067     lstrcpyA(dest, "control");
1068     str = PathCombineA(dest, "C:\\", too_long);
1069     todo_wine
1070     {
1071         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1072         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1073         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1074     }
1075
1076     /* try a directory longer than MAX_PATH */
1077     SetLastError(0xdeadbeef);
1078     lstrcpyA(dest, "control");
1079     str = PathCombineA(dest, too_long, "one\\two\\three");
1080     todo_wine
1081     {
1082         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1083         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1084         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1085     }
1086
1087     memset(one, 'b', HALF_LEN);
1088     memset(two, 'c', HALF_LEN);
1089     one[HALF_LEN - 1] = '\0';
1090     two[HALF_LEN - 1] = '\0';
1091
1092     /* destination string is longer than MAX_PATH, but not the constituent parts */
1093     SetLastError(0xdeadbeef);
1094     lstrcpyA(dest, "control");
1095     str = PathCombineA(dest, one, two);
1096     todo_wine
1097     {
1098         ok(str == NULL, "Expected str == NULL, got %p\n", str);
1099         ok(lstrlenA(dest) == 0, "Expected 0 length, got %i\n", lstrlenA(dest));
1100     }
1101     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1102 }
1103
1104 static void test_PathAddBackslash(void)
1105 {
1106     LPSTR str;
1107     char path[MAX_PATH];
1108     char too_long[LONG_LEN];
1109
1110     /* try a NULL path */
1111     SetLastError(0xdeadbeef);
1112     str = PathAddBackslashA(NULL);
1113     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1114     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1115
1116     /* try an empty path */
1117     path[0] = '\0';
1118     SetLastError(0xdeadbeef);
1119     str = PathAddBackslashA(path);
1120     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1121     ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
1122     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1123
1124     /* try a relative path */
1125     lstrcpyA(path, "one\\two");
1126     SetLastError(0xdeadbeef);
1127     str = PathAddBackslashA(path);
1128     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1129     ok(!lstrcmp(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
1130     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1131
1132     /* try periods */
1133     lstrcpyA(path, "one\\..\\two");
1134     SetLastError(0xdeadbeef);
1135     str = PathAddBackslashA(path);
1136     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1137     ok(!lstrcmp(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
1138     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1139
1140     /* try just a space */
1141     lstrcpyA(path, " ");
1142     SetLastError(0xdeadbeef);
1143     str = PathAddBackslashA(path);
1144     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1145     ok(!lstrcmp(path, " \\"), "Expected  \\, got %s\n", path);
1146     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1147
1148     /* path already has backslash */
1149     lstrcpyA(path, "C:\\one\\");
1150     SetLastError(0xdeadbeef);
1151     str = PathAddBackslashA(path);
1152     ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
1153     ok(!lstrcmp(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
1154     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1155
1156     memset(too_long, 'a', LONG_LEN);
1157     too_long[LONG_LEN - 1] = '\0';
1158
1159     /* path is longer than MAX_PATH */
1160     SetLastError(0xdeadbeef);
1161     str = PathAddBackslashA(too_long);
1162     ok(str == NULL, "Expected str == NULL, got %p\n", str);
1163     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1164 }
1165
1166 static void test_PathAppendA(void)
1167 {
1168     char path[MAX_PATH];
1169     char too_long[LONG_LEN];
1170     char one[HALF_LEN], two[HALF_LEN];
1171     BOOL res;
1172
1173     lstrcpy(path, "C:\\one");
1174
1175     /* try NULL pszMore */
1176     SetLastError(0xdeadbeef);
1177     res = PathAppendA(path, NULL);
1178     ok(!res, "Expected failure\n");
1179     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1180     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1181
1182     /* try empty pszMore */
1183     SetLastError(0xdeadbeef);
1184     res = PathAppendA(path, "");
1185     ok(res, "Expected success\n");
1186     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1187     ok(!lstrcmp(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
1188
1189     /* try NULL pszPath */
1190     SetLastError(0xdeadbeef);
1191     res = PathAppendA(NULL, "two\\three");
1192     ok(!res, "Expected failure\n");
1193     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1194
1195     /* try empty pszPath */
1196     path[0] = '\0';
1197     SetLastError(0xdeadbeef);
1198     res = PathAppendA(path, "two\\three");
1199     ok(res, "Expected success\n");
1200     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1201     ok(!lstrcmp(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
1202
1203     /* try empty pszPath and empty pszMore */
1204     path[0] = '\0';
1205     SetLastError(0xdeadbeef);
1206     res = PathAppendA(path, "");
1207     ok(res, "Expected success\n");
1208     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1209     ok(!lstrcmp(path, "\\"), "Expected \\, got %s\n", path);
1210
1211     /* try legit params */
1212     lstrcpy(path, "C:\\one");
1213     SetLastError(0xdeadbeef);
1214     res = PathAppendA(path, "two\\three");
1215     ok(res, "Expected success\n");
1216     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1217     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1218
1219     /* try pszPath with backslash after it */
1220     lstrcpy(path, "C:\\one\\");
1221     SetLastError(0xdeadbeef);
1222     res = PathAppendA(path, "two\\three");
1223     ok(res, "Expected success\n");
1224     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1225     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1226
1227     /* try pszMore with backslash before it */
1228     lstrcpy(path, "C:\\one");
1229     SetLastError(0xdeadbeef);
1230     res = PathAppendA(path, "\\two\\three");
1231     ok(res, "Expected success\n");
1232     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1233     ok(!lstrcmp(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
1234
1235     /* try pszMore with backslash after it */
1236     lstrcpy(path, "C:\\one");
1237     SetLastError(0xdeadbeef);
1238     res = PathAppendA(path, "two\\three\\");
1239     ok(res, "Expected success\n");
1240     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1241     ok(!lstrcmp(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
1242
1243     /* try spaces in pszPath */
1244     lstrcpy(path, "C: \\ one ");
1245     SetLastError(0xdeadbeef);
1246     res = PathAppendA(path, "two\\three");
1247     ok(res, "Expected success\n");
1248     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1249     ok(!lstrcmp(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
1250
1251     /* try spaces in pszMore */
1252     lstrcpy(path, "C:\\one");
1253     SetLastError(0xdeadbeef);
1254     res = PathAppendA(path, " two \\ three ");
1255     ok(res, "Expected success\n");
1256     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1257     ok(!lstrcmp(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
1258
1259     /* pszPath is too long */
1260     memset(too_long, 'a', LONG_LEN);
1261     too_long[LONG_LEN - 1] = '\0';
1262     SetLastError(0xdeadbeef);
1263     res = PathAppendA(too_long, "two\\three");
1264     todo_wine
1265     {
1266         ok(!res, "Expected failure\n");
1267         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1268         ok(lstrlen(too_long) == 0, "Expected length of too_long to be zero, got %i\n", lstrlen(too_long));
1269     }
1270
1271     /* pszMore is too long */
1272     lstrcpy(path, "C:\\one");
1273     memset(too_long, 'a', LONG_LEN);
1274     too_long[LONG_LEN - 1] = '\0';
1275     SetLastError(0xdeadbeef);
1276     res = PathAppendA(path, too_long);
1277     todo_wine
1278     {
1279         ok(!res, "Expected failure\n");
1280         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1281         ok(lstrlen(path) == 0, "Expected length of path to be zero, got %i\n", lstrlen(path));
1282     }
1283
1284     /* both params combined are too long */
1285     memset(one, 'a', HALF_LEN);
1286     one[HALF_LEN - 1] = '\0';
1287     memset(two, 'b', HALF_LEN);
1288     two[HALF_LEN - 1] = '\0';
1289     SetLastError(0xdeadbeef);
1290     res = PathAppendA(one, two);
1291     todo_wine
1292     {
1293         ok(!res, "Expected failure\n");
1294         ok(lstrlen(one) == 0, "Expected length of one to be zero, got %i\n", lstrlen(one));
1295     }
1296     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1297 }
1298
1299 static void test_PathCanonicalizeA(void)
1300 {
1301     char dest[MAX_PATH];
1302     char too_long[LONG_LEN];
1303     BOOL res;
1304
1305     /* try a NULL source */
1306     lstrcpy(dest, "test");
1307     SetLastError(0xdeadbeef);
1308     res = PathCanonicalizeA(dest, NULL);
1309     ok(!res, "Expected failure\n");
1310     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1311        "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1312     todo_wine
1313     {
1314         ok(!lstrcmp(dest, "test"), "Expected test, got %s\n", dest);
1315     }
1316
1317     /* try an empty source */
1318     lstrcpy(dest, "test");
1319     SetLastError(0xdeadbeef);
1320     res = PathCanonicalizeA(dest, "");
1321     ok(res, "Expected success\n");
1322     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1323     ok(!lstrcmp(dest, "\\"), "Expected \\, got %s\n", dest);
1324
1325     /* try a NULL dest */
1326     SetLastError(0xdeadbeef);
1327     res = PathCanonicalizeA(NULL, "C:\\");
1328     ok(!res, "Expected failure\n");
1329     ok(GetLastError() == ERROR_INVALID_PARAMETER, 
1330        "Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
1331
1332     /* try empty dest */
1333     dest[0] = '\0';
1334     SetLastError(0xdeadbeef);
1335     res = PathCanonicalizeA(dest, "C:\\");
1336     ok(res, "Expected success\n");
1337     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1338     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1339
1340     /* try non-empty dest */
1341     lstrcpy(dest, "test");
1342     SetLastError(0xdeadbeef);
1343     res = PathCanonicalizeA(dest, "C:\\");
1344     ok(res, "Expected success\n");
1345     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1346     ok(!lstrcmp(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1347
1348     /* try a space for source */
1349     lstrcpy(dest, "test");
1350     SetLastError(0xdeadbeef);
1351     res = PathCanonicalizeA(dest, " ");
1352     ok(res, "Expected success\n");
1353     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1354     ok(!lstrcmp(dest, " "), "Expected ' ', got %s\n", dest);
1355
1356     /* try a relative path */
1357     lstrcpy(dest, "test");
1358     SetLastError(0xdeadbeef);
1359     res = PathCanonicalizeA(dest, "one\\two");
1360     ok(res, "Expected success\n");
1361     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1362     ok(!lstrcmp(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
1363
1364     /* try current dir and previous dir */
1365     lstrcpy(dest, "test");
1366     SetLastError(0xdeadbeef);
1367     res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
1368     ok(res, "Expected success\n");
1369     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1370     ok(!lstrcmp(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
1371
1372     /* try simple forward slashes */
1373     lstrcpy(dest, "test");
1374     SetLastError(0xdeadbeef);
1375     res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
1376     ok(res, "Expected success\n");
1377     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1378     ok(!lstrcmp(dest, "C:\\one/two/three\\four/five\\six"),
1379        "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
1380
1381     /* try simple forward slashes with same dir */
1382     lstrcpy(dest, "test");
1383     SetLastError(0xdeadbeef);
1384     res = PathCanonicalizeA(dest, "C:\\one/.\\two");
1385     ok(res, "Expected success\n");
1386     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1387     ok(!lstrcmp(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
1388
1389     /* try simple forward slashes with change dir */
1390     lstrcpy(dest, "test");
1391     SetLastError(0xdeadbeef);
1392     res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
1393     ok(res, "Expected success\n");
1394     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1395     ok(!lstrcmp(dest, "C:\\one/."), "Expected C:\\one/., got %s\n", dest);
1396
1397     /* try forward slashes with change dirs
1398      * NOTE: if there is a forward slash in between two backslashes,
1399      * everything in between the two backslashes is considered on dir
1400      */
1401     lstrcpy(dest, "test");
1402     SetLastError(0xdeadbeef);
1403     res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
1404     ok(res, "Expected success\n");
1405     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1406     ok(!lstrcmp(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
1407
1408     /* try src is too long */
1409     memset(too_long, 'a', LONG_LEN);
1410     too_long[LONG_LEN - 1] = '\0';
1411     lstrcpy(dest, "test");
1412     SetLastError(0xdeadbeef);
1413     res = PathCanonicalizeA(dest, too_long);
1414     todo_wine
1415     {
1416         ok(!res, "Expected failure\n");
1417         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1418     }
1419     ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long));
1420 }
1421
1422 static void test_PathFindExtensionA(void)
1423 {
1424     LPSTR ext;
1425     char path[MAX_PATH];
1426     char too_long[LONG_LEN];
1427
1428     /* try a NULL path */
1429     SetLastError(0xdeadbeef);
1430     ext = PathFindExtensionA(NULL);
1431     ok(ext == NULL, "Expected NULL, got %p\n", ext);
1432     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1433
1434     /* try an empty path */
1435     path[0] = '\0';
1436     SetLastError(0xdeadbeef);
1437     ext = PathFindExtensionA(path);
1438     ok(ext == path, "Expected ext == path, got %p\n", ext);
1439     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1440     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1441
1442     /* try a path without an extension */
1443     lstrcpy(path, "file");
1444     SetLastError(0xdeadbeef);
1445     ext = PathFindExtensionA(path);
1446     ok(ext == path + lstrlen(path), "Expected ext == path, got %p\n", ext);
1447     ok(lstrlen(ext) == 0, "Expected length 0, got %i\n", lstrlen(ext));
1448     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1449
1450     /* try a path with an extension */
1451     lstrcpy(path, "file.txt");
1452     SetLastError(0xdeadbeef);
1453     ext = PathFindExtensionA(path);
1454     ok(ext == path + lstrlen("file"),
1455        "Expected ext == path + lstrlen(\"file\"), got %p\n", ext);
1456     ok(!lstrcmp(ext, ".txt"), "Expected .txt, got %s\n", ext);
1457     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1458
1459     /* try a path with two extensions */
1460     lstrcpy(path, "file.txt.doc");
1461     SetLastError(0xdeadbeef);
1462     ext = PathFindExtensionA(path);
1463     ok(ext == path + lstrlen("file.txt"),
1464        "Expected ext == path + lstrlen(\"file.txt\"), got %p\n", ext);
1465     ok(!lstrcmp(ext, ".doc"), "Expected .txt, got %s\n", ext);
1466     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1467
1468     /* try a path longer than MAX_PATH without an extension*/
1469     memset(too_long, 'a', LONG_LEN);
1470     too_long[LONG_LEN - 1] = '\0';
1471     SetLastError(0xdeadbeef);
1472     ext = PathFindExtensionA(too_long);
1473     ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
1474     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1475
1476     /* try a path longer than MAX_PATH with an extension*/
1477     memset(too_long, 'a', LONG_LEN);
1478     too_long[LONG_LEN - 1] = '\0';
1479     lstrcpy(too_long + 300, ".abcde");
1480     too_long[lstrlen(too_long)] = 'a';
1481     SetLastError(0xdeadbeef);
1482     ext = PathFindExtensionA(too_long);
1483     ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1484     ok(lstrlen(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlen(ext));
1485     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1486 }
1487
1488 static void test_PathBuildRootA(void)
1489 {
1490     LPSTR root;
1491     char path[10];
1492     char root_expected[26][4];
1493     char drive;
1494     int j;
1495
1496     /* set up the expected paths */
1497     for (drive = 'A'; drive <= 'Z'; drive++)
1498         sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1499
1500     /* test the expected values */
1501     for (j = 0; j < 26; j++)
1502     {
1503         SetLastError(0xdeadbeef);
1504         lstrcpy(path, "aaaaaaaaa");
1505         root = PathBuildRootA(path, j);
1506         ok(root == path, "Expected root == path, got %p\n", root);
1507         ok(!lstrcmp(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1508         ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1509     }
1510
1511     /* test a negative drive number */
1512     SetLastError(0xdeadbeef);
1513     lstrcpy(path, "aaaaaaaaa");
1514     root = PathBuildRootA(path, -1);
1515     ok(root == path, "Expected root == path, got %p\n", root);
1516     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1517     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1518
1519     /* test a drive number greater than 25 */
1520     SetLastError(0xdeadbeef);
1521     lstrcpy(path, "aaaaaaaaa");
1522     root = PathBuildRootA(path, 26);
1523     ok(root == path, "Expected root == path, got %p\n", root);
1524     ok(!lstrcmp(path, "aaaaaaaaa"), "Expected aaaaaaaaa, got %s\n", path);
1525     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1526
1527     /* length of path is less than 4 */
1528     SetLastError(0xdeadbeef);
1529     lstrcpy(path, "aa");
1530     root = PathBuildRootA(path, 0);
1531     ok(root == path, "Expected root == path, got %p\n", root);
1532     ok(!lstrcmp(path, "A:\\"), "Expected A:\\, got %s\n", path);
1533     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1534
1535     /* path is NULL */
1536     SetLastError(0xdeadbeef);
1537     root = PathBuildRootA(NULL, 0);
1538     ok(root == NULL, "Expected root == NULL, got %p\n", root);
1539     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1540 }
1541
1542 static void test_PathCommonPrefixA(void)
1543 {
1544     char path1[MAX_PATH], path2[MAX_PATH];
1545     char out[MAX_PATH];
1546     int count;
1547
1548     /* test NULL path1 */
1549     SetLastError(0xdeadbeef);
1550     lstrcpy(path2, "C:\\");
1551     lstrcpy(out, "aaa");
1552     count = PathCommonPrefixA(NULL, path2, out);
1553     ok(count == 0, "Expected 0, got %i\n", count);
1554     todo_wine
1555     {
1556         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1557     }
1558     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1559     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1560
1561     /* test NULL path2 */
1562     SetLastError(0xdeadbeef);
1563     lstrcpy(path1, "C:\\");
1564     lstrcpy(out, "aaa");
1565     count = PathCommonPrefixA(path1, NULL, out);
1566     ok(count == 0, "Expected 0, got %i\n", count);
1567     todo_wine
1568     {
1569         ok(!lstrcmp(out, "aaa"), "Expected aaa, got %s\n", out);
1570     }
1571     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1572     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1573
1574     /* test empty path1 */
1575     SetLastError(0xdeadbeef);
1576     path1[0] = '\0';
1577     lstrcpy(path2, "C:\\");
1578     lstrcpy(out, "aaa");
1579     count = PathCommonPrefixA(path1, path2, out);
1580     ok(count == 0, "Expected 0, got %i\n", count);
1581     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1582     ok(lstrlen(path1) == 0, "Expected 0 length path1, got %i\n", lstrlen(path1));
1583     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1584     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1585
1586     /* test empty path1 */
1587     SetLastError(0xdeadbeef);
1588     path2[0] = '\0';
1589     lstrcpy(path1, "C:\\");
1590     lstrcpy(out, "aaa");
1591     count = PathCommonPrefixA(path1, path2, out);
1592     ok(count == 0, "Expected 0, got %i\n", count);
1593     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1594     ok(lstrlen(path2) == 0, "Expected 0 length path2, got %i\n", lstrlen(path2));
1595     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1596     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1597
1598     /* paths are legit, out is NULL */
1599     SetLastError(0xdeadbeef);
1600     lstrcpy(path1, "C:\\");
1601     lstrcpy(path2, "C:\\");
1602     count = PathCommonPrefixA(path1, path2, NULL);
1603     ok(count == 3, "Expected 3, got %i\n", count);
1604     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1605     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1606     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1607
1608     /* all parameters legit */
1609     SetLastError(0xdeadbeef);
1610     lstrcpy(path1, "C:\\");
1611     lstrcpy(path2, "C:\\");
1612     lstrcpy(out, "aaa");
1613     count = PathCommonPrefixA(path1, path2, out);
1614     ok(count == 3, "Expected 3, got %i\n", count);
1615     ok(!lstrcmp(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1616     ok(!lstrcmp(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1617     ok(!lstrcmp(out, "C:\\"), "Expected C:\\, got %s\n", out);
1618     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1619
1620     /* path1 and path2 not the same, but common prefix */
1621     SetLastError(0xdeadbeef);
1622     lstrcpy(path1, "C:\\one\\two");
1623     lstrcpy(path2, "C:\\one\\three");
1624     lstrcpy(out, "aaa");
1625     count = PathCommonPrefixA(path1, path2, out);
1626     ok(count == 6, "Expected 6, got %i\n", count);
1627     ok(!lstrcmp(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1628     ok(!lstrcmp(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1629     ok(!lstrcmp(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1630     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1631
1632     /* try . prefix */
1633     SetLastError(0xdeadbeef);
1634     lstrcpy(path1, "one\\.two");
1635     lstrcpy(path2, "one\\.three");
1636     lstrcpy(out, "aaa");
1637     count = PathCommonPrefixA(path1, path2, out);
1638     ok(count == 3, "Expected 3, got %i\n", count);
1639     ok(!lstrcmp(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1640     ok(!lstrcmp(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1641     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1642     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1643
1644     /* try .. prefix */
1645     SetLastError(0xdeadbeef);
1646     lstrcpy(path1, "one\\..two");
1647     lstrcpy(path2, "one\\..three");
1648     lstrcpy(out, "aaa");
1649     count = PathCommonPrefixA(path1, path2, out);
1650     ok(count == 3, "Expected 3, got %i\n", count);
1651     ok(!lstrcmp(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1652     ok(!lstrcmp(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1653     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1654     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1655
1656     /* try ... prefix */
1657     SetLastError(0xdeadbeef);
1658     lstrcpy(path1, "one\\...two");
1659     lstrcpy(path2, "one\\...three");
1660     lstrcpy(out, "aaa");
1661     count = PathCommonPrefixA(path1, path2, out);
1662     ok(count == 3, "Expected 3, got %i\n", count);
1663     ok(!lstrcmp(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1664     ok(!lstrcmp(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1665     ok(!lstrcmp(out, "one"), "Expected one, got %s\n", out);
1666     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1667
1668     /* try .\ prefix */
1669     SetLastError(0xdeadbeef);
1670     lstrcpy(path1, "one\\.\\two");
1671     lstrcpy(path2, "one\\.\\three");
1672     lstrcpy(out, "aaa");
1673     count = PathCommonPrefixA(path1, path2, out);
1674     ok(count == 5, "Expected 5, got %i\n", count);
1675     ok(!lstrcmp(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1676     ok(!lstrcmp(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1677     ok(!lstrcmp(out, "one\\."), "Expected one\\., got %s\n", out);
1678     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1679
1680     /* try ..\ prefix */
1681     SetLastError(0xdeadbeef);
1682     lstrcpy(path1, "one\\..\\two");
1683     lstrcpy(path2, "one\\..\\three");
1684     lstrcpy(out, "aaa");
1685     count = PathCommonPrefixA(path1, path2, out);
1686     ok(count == 6, "Expected 6, got %i\n", count);
1687     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1688     ok(!lstrcmp(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1689     ok(!lstrcmp(out, "one\\.."), "Expected one\\.., got %s\n", out);
1690     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1691
1692     /* try ...\\ prefix */
1693     SetLastError(0xdeadbeef);
1694     lstrcpy(path1, "one\\...\\two");
1695     lstrcpy(path2, "one\\...\\three");
1696     lstrcpy(out, "aaa");
1697     count = PathCommonPrefixA(path1, path2, out);
1698     ok(count == 7, "Expected 7, got %i\n", count);
1699     ok(!lstrcmp(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1700     ok(!lstrcmp(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1701     ok(!lstrcmp(out, "one\\..."), "Expected one\\..., got %s\n", out);
1702     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1703
1704     /* try prefix that is not an msdn labeled prefix type */
1705     SetLastError(0xdeadbeef);
1706     lstrcpy(path1, "same");
1707     lstrcpy(path2, "same");
1708     lstrcpy(out, "aaa");
1709     count = PathCommonPrefixA(path1, path2, out);
1710     ok(count == 4, "Expected 4, got %i\n", count);
1711     ok(!lstrcmp(path1, "same"), "Expected same, got %s\n", path1);
1712     ok(!lstrcmp(path2, "same"), "Expected same, got %s\n", path2);
1713     ok(!lstrcmp(out, "same"), "Expected same, got %s\n", out);
1714     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1715
1716     /* try . after directory */
1717     SetLastError(0xdeadbeef);
1718     lstrcpy(path1, "one\\mid.\\two");
1719     lstrcpy(path2, "one\\mid.\\three");
1720     lstrcpy(out, "aaa");
1721     count = PathCommonPrefixA(path1, path2, out);
1722     ok(count == 8, "Expected 8, got %i\n", count);
1723     ok(!lstrcmp(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1724     ok(!lstrcmp(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1725     ok(!lstrcmp(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1726     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1727
1728     /* try . in the middle of a directory */
1729     SetLastError(0xdeadbeef);
1730     lstrcpy(path1, "one\\mid.end\\two");
1731     lstrcpy(path2, "one\\mid.end\\three");
1732     lstrcpy(out, "aaa");
1733     count = PathCommonPrefixA(path1, path2, out);
1734     ok(count == 11, "Expected 11, got %i\n", count);
1735     ok(!lstrcmp(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1736     ok(!lstrcmp(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1737     ok(!lstrcmp(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1738     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1739
1740     /* try comparing a .. with the expanded path */
1741     SetLastError(0xdeadbeef);
1742     lstrcpy(path1, "one\\..\\two");
1743     lstrcpy(path2, "two");
1744     lstrcpy(out, "aaa");
1745     count = PathCommonPrefixA(path1, path2, out);
1746     ok(count == 0, "Expected 0, got %i\n", count);
1747     ok(!lstrcmp(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1748     ok(!lstrcmp(path2, "two"), "Expected two, got %s\n", path2);
1749     ok(lstrlen(out) == 0, "Expected 0 length out, got %i\n", lstrlen(out));
1750     ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %ld\n", GetLastError());
1751 }
1752
1753 START_TEST(path)
1754 {
1755   hShlwapi = LoadLibraryA("shlwapi.dll");
1756   if (!hShlwapi) return;
1757
1758   test_UrlHash();
1759   test_UrlGetPart();
1760   test_UrlCanonicalize();
1761   test_UrlEscape();
1762   test_UrlCombine();
1763   test_UrlCreateFromPath();
1764   test_UrlIs();
1765   test_UrlUnescape();
1766
1767   test_PathSearchAndQualify();
1768   test_PathCreateFromUrl();
1769   test_PathIsUrl();
1770
1771   test_PathAddBackslash();
1772   test_PathMakePretty();
1773   test_PathMatchSpec();
1774
1775   /* For whatever reason, PathIsValidCharA and PathAppendA share the same
1776    * ordinal number in some native versions. Check this to prevent a crash.
1777    */
1778   pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1779   if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
1780   {
1781     test_PathIsValidCharA();
1782
1783      pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1784      if (pPathIsValidCharW) test_PathIsValidCharW();
1785   }
1786
1787   pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1788   if (pPathCombineW)
1789     test_PathCombineW();
1790
1791   test_PathCombineA();
1792   test_PathAppendA();
1793   test_PathCanonicalizeA();
1794   test_PathFindExtensionA();
1795   test_PathBuildRootA();
1796   test_PathCommonPrefixA();
1797 }