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