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