soup-multipart-input-stream: belatedly add .h file to soup.h
[platform/upstream/libsoup.git] / tests / uri-parsing.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 #include "test-utils.h"
4
5 static struct {
6         const char *uri_string, *result;
7         const SoupURI bits;
8 } abs_tests[] = {
9         { "foo:", "foo:",
10           { "foo", NULL, NULL, NULL, 0, "", NULL, NULL } },
11         { "file:/dev/null", "file:/dev/null",
12           { "file", NULL, NULL, NULL, 0, "/dev/null", NULL, NULL } },
13         { "file:///dev/null", "file:///dev/null",
14           { "file", NULL, NULL, "", 0, "/dev/null", NULL, NULL } },
15         { "ftp://user@host/path", "ftp://user@host/path",
16           { "ftp", "user", NULL, "host", 21, "/path", NULL, NULL } },
17         { "ftp://user@host:9999/path", "ftp://user@host:9999/path",
18           { "ftp", "user", NULL, "host", 9999, "/path", NULL, NULL } },
19         { "ftp://user:password@host/path", "ftp://user@host/path",
20           { "ftp", "user", "password", "host", 21, "/path", NULL, NULL } },
21         { "ftp://user:password@host:9999/path", "ftp://user@host:9999/path",
22           { "ftp", "user", "password", "host", 9999, "/path", NULL, NULL } },
23         { "ftp://user:password@host", "ftp://user@host",
24           { "ftp", "user", "password", "host", 21, "", NULL, NULL } },
25         { "http://us%65r@host", "http://user@host/",
26           { "http", "user", NULL, "host", 80, "/", NULL, NULL } },
27         { "http://us%40r@host", "http://us%40r@host/",
28           { "http", "us\x40r", NULL, "host", 80, "/", NULL, NULL } },
29         { "http://us%3ar@host", "http://us%3Ar@host/",
30           { "http", "us\x3ar", NULL, "host", 80, "/", NULL, NULL } },
31         { "http://us%2fr@host", "http://us%2Fr@host/",
32           { "http", "us\x2fr", NULL, "host", 80, "/", NULL, NULL } },
33         { "http://us%3fr@host", "http://us%3Fr@host/",
34           { "http", "us\x3fr", NULL, "host", 80, "/", NULL, NULL } },
35         { "http://host?query", "http://host/?query",
36           { "http", NULL, NULL, "host", 80, "/", "query", NULL } },
37         { "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue&param=value",
38           "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue&param=value",
39           { "http", NULL, NULL, "host", 80, "/path", "query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue&param=value", NULL } },
40         { "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F",
41           "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F",
42           { "http", NULL, NULL, "control-chars", 80, "/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F", NULL, NULL } },
43         { "http://space/%20",
44           "http://space/%20",
45           { "http", NULL, NULL, "space", 80, "/%20", NULL, NULL } },
46         { "http://delims/%3C%3E%23%25%22",
47           "http://delims/%3C%3E%23%25%22",
48           { "http", NULL, NULL, "delims", 80, "/%3C%3E%23%25%22", NULL, NULL } },
49         { "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60",
50           "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60",
51           { "http", NULL, NULL, "unwise-chars", 80, "/%7B%7D%7C%5C%5E%5B%5D%60", NULL, NULL } },
52
53         /* From RFC 2732 */
54         { "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html",
55           "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html",
56           { "http", NULL, NULL, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80, "/index.html", NULL, NULL } },
57         { "http://[1080:0:0:0:8:800:200C:417A]/index.html",
58           "http://[1080:0:0:0:8:800:200C:417A]/index.html",
59           { "http", NULL, NULL, "1080:0:0:0:8:800:200C:417A", 80, "/index.html", NULL, NULL } },
60         { "http://[3ffe:2a00:100:7031::1]",
61           "http://[3ffe:2a00:100:7031::1]/",
62           { "http", NULL, NULL, "3ffe:2a00:100:7031::1", 80, "/", NULL, NULL } },
63         { "http://[1080::8:800:200C:417A]/foo",
64           "http://[1080::8:800:200C:417A]/foo",
65           { "http", NULL, NULL, "1080::8:800:200C:417A", 80, "/foo", NULL, NULL } },
66         { "http://[::192.9.5.5]/ipng",
67           "http://[::192.9.5.5]/ipng",
68           { "http", NULL, NULL, "::192.9.5.5", 80, "/ipng", NULL, NULL } },
69         { "http://[::FFFF:129.144.52.38]:80/index.html",
70           "http://[::FFFF:129.144.52.38]/index.html",
71           { "http", NULL, NULL, "::FFFF:129.144.52.38", 80, "/index.html", NULL, NULL } },
72         { "http://[2010:836B:4179::836B:4179]",
73           "http://[2010:836B:4179::836B:4179]/",
74           { "http", NULL, NULL, "2010:836B:4179::836B:4179", 80, "/", NULL, NULL } },
75
76         /* Try to recover certain kinds of invalid URIs */
77         { "http://host/path with spaces",
78           "http://host/path%20with%20spaces",
79           { "http", NULL, NULL, "host", 80, "/path%20with%20spaces", NULL, NULL } },
80         { "  http://host/path", "http://host/path",
81           { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
82         { "http://host/path  ", "http://host/path",
83           { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
84         { "http://host  ", "http://host/",
85           { "http", NULL, NULL, "host", 80, "/", NULL, NULL } },
86         { "http://host:999  ", "http://host:999/",
87           { "http", NULL, NULL, "host", 999, "/", NULL, NULL } },
88         { "http://host/pa\nth", "http://host/path",
89           { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
90         { "http:\r\n//host/path", "http://host/path",
91           { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
92         { "http://\thost/path", "http://host/path",
93           { "http", NULL, NULL, "host", 80, "/path", NULL, NULL } },
94
95         /* Bug 594405; 0-length is different from not-present */
96         { "http://host/path?", "http://host/path?",
97           { "http", NULL, NULL, "host", 80, "/path", "", NULL } },
98         { "http://host/path#", "http://host/path#",
99           { "http", NULL, NULL, "host", 80, "/path", NULL, "" } },
100
101         /* Bug 590524; ignore badly-%-encoding */
102         { "http://host/path%", "http://host/path%",
103           { "http", NULL, NULL, "host", 80, "/path%", NULL, NULL } },
104         { "http://h%ost/path", "http://h%25ost/path",
105           { "http", NULL, NULL, "h%ost", 80, "/path", NULL, NULL } },
106         { "http://host/path%%", "http://host/path%%",
107           { "http", NULL, NULL, "host", 80, "/path%%", NULL, NULL } },
108         { "http://host/path%%%", "http://host/path%%%",
109           { "http", NULL, NULL, "host", 80, "/path%%%", NULL, NULL } },
110         { "http://host/path%/x/", "http://host/path%/x/",
111           { "http", NULL, NULL, "host", 80, "/path%/x/", NULL, NULL } },
112         { "http://host/path%0x/", "http://host/path%0x/",
113           { "http", NULL, NULL, "host", 80, "/path%0x/", NULL, NULL } },
114         { "http://host/path%ax", "http://host/path%ax",
115           { "http", NULL, NULL, "host", 80, "/path%ax", NULL, NULL } },
116
117         /* Bug 662806; %-encode non-ASCII characters */
118         { "http://host/p\xc3\xa4th/", "http://host/p%C3%A4th/",
119           { "http", NULL, NULL, "host", 80, "/p%C3%A4th/", NULL, NULL } },
120
121         { "HTTP:////////////////", "http:////////////////",
122           { "http", NULL, NULL, "", 80, "//////////////", NULL, NULL } },
123 };
124 static int num_abs_tests = G_N_ELEMENTS(abs_tests);
125
126 /* From RFC 3986. */
127 static const char *base = "http://a/b/c/d;p?q";
128 static struct {
129         const char *uri_string, *result;
130         const SoupURI bits;
131 } rel_tests[] = {
132         { "g:h", "g:h",
133           { "g", NULL, NULL, NULL, 0, "h", NULL, NULL } },
134         { "g", "http://a/b/c/g",
135           { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, NULL } },
136         { "./g", "http://a/b/c/g",
137           { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, NULL } },
138         { "g/", "http://a/b/c/g/",
139           { "http", NULL, NULL, "a", 80, "/b/c/g/", NULL, NULL } },
140         { "/g", "http://a/g",
141           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
142         { "//g", "http://g/",
143           { "http", NULL, NULL, "g", 80, "/", NULL, NULL } },
144         { "?y", "http://a/b/c/d;p?y",
145           { "http", NULL, NULL, "a", 80, "/b/c/d;p", "y", NULL } },
146         { "g?y", "http://a/b/c/g?y",
147           { "http", NULL, NULL, "a", 80, "/b/c/g", "y", NULL } },
148         { "#s", "http://a/b/c/d;p?q#s",
149           { "http", NULL, NULL, "a", 80, "/b/c/d;p", "q", "s" } },
150         { "g#s", "http://a/b/c/g#s",
151           { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s" } },
152         { "g?y#s", "http://a/b/c/g?y#s",
153           { "http", NULL, NULL, "a", 80, "/b/c/g", "y", "s" } },
154         { ";x", "http://a/b/c/;x",
155           { "http", NULL, NULL, "a", 80, "/b/c/;x", NULL, NULL } },
156         { "g;x", "http://a/b/c/g;x",
157           { "http", NULL, NULL, "a", 80, "/b/c/g;x", NULL, NULL } },
158         { "g;x?y#s", "http://a/b/c/g;x?y#s",
159           { "http", NULL, NULL, "a", 80, "/b/c/g;x", "y", "s" } },
160         { ".", "http://a/b/c/",
161           { "http", NULL, NULL, "a", 80, "/b/c/", NULL, NULL } },
162         { "./", "http://a/b/c/",
163           { "http", NULL, NULL, "a", 80, "/b/c/", NULL, NULL } },
164         { "..", "http://a/b/",
165           { "http", NULL, NULL, "a", 80, "/b/", NULL, NULL } },
166         { "../", "http://a/b/",
167           { "http", NULL, NULL, "a", 80, "/b/", NULL, NULL } },
168         { "../g", "http://a/b/g",
169           { "http", NULL, NULL, "a", 80, "/b/g", NULL, NULL } },
170         { "../..", "http://a/",
171           { "http", NULL, NULL, "a", 80, "/", NULL, NULL } },
172         { "../../", "http://a/",
173           { "http", NULL, NULL, "a", 80, "/", NULL, NULL } },
174         { "../../g", "http://a/g",
175           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
176         { "", "http://a/b/c/d;p?q",
177           { "http", NULL, NULL, "a", 80, "/b/c/d;p", "q", NULL } },
178         { "../../../g", "http://a/g",
179           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
180         { "../../../../g", "http://a/g",
181           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
182         { "/./g", "http://a/g",
183           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
184         { "/../g", "http://a/g",
185           { "http", NULL, NULL, "a", 80, "/g", NULL, NULL } },
186         { "g.", "http://a/b/c/g.",
187           { "http", NULL, NULL, "a", 80, "/b/c/g.", NULL, NULL } },
188         { ".g", "http://a/b/c/.g",
189           { "http", NULL, NULL, "a", 80, "/b/c/.g", NULL, NULL } },
190         { "g..", "http://a/b/c/g..",
191           { "http", NULL, NULL, "a", 80, "/b/c/g..", NULL, NULL } },
192         { "..g", "http://a/b/c/..g",
193           { "http", NULL, NULL, "a", 80, "/b/c/..g", NULL, NULL } },
194         { "./../g", "http://a/b/g",
195           { "http", NULL, NULL, "a", 80, "/b/g", NULL, NULL } },
196         { "./g/.", "http://a/b/c/g/",
197           { "http", NULL, NULL, "a", 80, "/b/c/g/", NULL, NULL } },
198         { "g/./h", "http://a/b/c/g/h",
199           { "http", NULL, NULL, "a", 80, "/b/c/g/h", NULL, NULL } },
200         { "g/../h", "http://a/b/c/h",
201           { "http", NULL, NULL, "a", 80, "/b/c/h", NULL, NULL } },
202         { "g;x=1/./y", "http://a/b/c/g;x=1/y",
203           { "http", NULL, NULL, "a", 80, "/b/c/g;x=1/y", NULL, NULL } },
204         { "g;x=1/../y", "http://a/b/c/y",
205           { "http", NULL, NULL, "a", 80, "/b/c/y", NULL, NULL } },
206         { "g?y/./x", "http://a/b/c/g?y/./x",
207           { "http", NULL, NULL, "a", 80, "/b/c/g", "y/./x", NULL } },
208         { "g?y/../x", "http://a/b/c/g?y/../x",
209           { "http", NULL, NULL, "a", 80, "/b/c/g", "y/../x", NULL } },
210         { "g#s/./x", "http://a/b/c/g#s/./x",
211           { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s/./x" } },
212         { "g#s/../x", "http://a/b/c/g#s/../x",
213           { "http", NULL, NULL, "a", 80, "/b/c/g", NULL, "s/../x" } },
214
215         /* RFC 3986 notes that some old parsers will parse this as
216          * a relative URL ("http://a/b/c/g"), but it should be
217          * interpreted as absolute. libsoup should parse it
218          * correctly as being absolute, but then reject it since it's
219          * an http URL with no host.
220          */
221         { "http:g", NULL, { NULL } }
222 };
223 static int num_rel_tests = G_N_ELEMENTS(rel_tests);
224
225 static struct {
226         const char *one, *two;
227 } eq_tests[] = {
228         { "example://a/b/c/%7Bfoo%7D", "eXAMPLE://a/./b/../b/%63/%7Bfoo%7D" },
229         { "http://example.com", "http://example.com/" },
230         /* From RFC 2616 */
231         { "http://abc.com:80/~smith/home.html", "http://abc.com:80/~smith/home.html" },
232         { "http://abc.com:80/~smith/home.html", "http://ABC.com/%7Esmith/home.html" },
233         { "http://abc.com:80/~smith/home.html", "http://ABC.com:/%7esmith/home.html" },
234 };
235 static int num_eq_tests = G_N_ELEMENTS(eq_tests);
236
237 #define test_cmpstr(a, b) _test_cmpstr (#a, #b, a, b)
238
239 static gboolean
240 _test_cmpstr (const char *got_desc,
241               const char *exp_desc,
242               const char *got,
243               const char *expected)
244 {
245         if (got == expected)
246                 return TRUE;
247
248         if (got == NULL) {
249                 debug_printf (1, "ERR\n  %s = NULL, expected %s = \"%s\"\n",
250                               got_desc, exp_desc, expected);
251                 return FALSE;
252         }
253
254         if (expected == NULL) {
255                 debug_printf (1, "ERR\n  %s = \"%s\", expected %s = NULL\n",
256                               got_desc, got, exp_desc);
257                 return FALSE;
258         }
259
260         if (strcmp (got, expected) != 0) {
261                 debug_printf (1, "ERR\n  %s = \"%s\", expected %s = \"%s\"\n",
262                               got_desc, got, exp_desc, expected);
263                 return FALSE;
264         }
265
266         return TRUE;
267 }
268
269 static gboolean
270 do_uri (SoupURI *base_uri, const char *base_str,
271         const char *in_uri, const char *out_uri,
272         const SoupURI *bits)
273 {
274         SoupURI *uri;
275         char *uri_string;
276
277         if (base_uri) {
278                 debug_printf (1, "<%s> + <%s> = <%s>? ", base_str, in_uri,
279                               out_uri ? out_uri : "ERR");
280                 uri = soup_uri_new_with_base (base_uri, in_uri);
281         } else {
282                 debug_printf (1, "<%s> => <%s>? ", in_uri,
283                               out_uri ? out_uri : "ERR");
284                 uri = soup_uri_new (in_uri);
285         }
286
287         if (!uri) {
288                 if (out_uri) {
289                         debug_printf (1, "ERR\n  Could not parse %s\n", in_uri);
290                         return FALSE;
291                 } else {
292                         debug_printf (1, "OK\n");
293                         return TRUE;
294                 }
295         }
296
297         if (bits != NULL) {
298                 gboolean failed = FALSE;
299
300                 if (!test_cmpstr (uri->scheme, bits->scheme))
301                         failed = TRUE;
302
303                 if (!test_cmpstr (uri->user, bits->user))
304                         failed = TRUE;
305
306                 if (!test_cmpstr (uri->password, bits->password))
307                         failed = TRUE;
308
309                 if (!test_cmpstr (uri->host, bits->host))
310                         failed = TRUE;
311
312                 if (uri->port != bits->port) {
313                         debug_printf (1, "ERR\n  port was %u, expected %u\n",
314                                       uri->port, bits->port);
315                         failed = TRUE;
316                 }
317
318                 if (!test_cmpstr (uri->path, bits->path))
319                         failed = TRUE;
320
321                 if (!test_cmpstr (uri->query, bits->query))
322                         failed = TRUE;
323
324                 if (!test_cmpstr (uri->fragment, bits->fragment))
325                         failed = TRUE;
326
327                 if (failed)
328                         return FALSE;
329         }
330
331         uri_string = soup_uri_to_string (uri, FALSE);
332         soup_uri_free (uri);
333
334         if (!out_uri) {
335                 debug_printf (1, "ERR\n  Got %s\n", uri_string);
336                 return FALSE;
337         }
338
339         if (strcmp (uri_string, out_uri) != 0) {
340                 debug_printf (1, "NO\n  Unparses to <%s>\n", uri_string);
341                 g_free (uri_string);
342                 return FALSE;
343         }
344         g_free (uri_string);
345
346         debug_printf (1, "OK\n");
347         return TRUE;
348 }
349
350 static void
351 do_soup_uri_null_tests (void)
352 {
353         SoupURI *uri, *uri2;
354         char *uri_string;
355
356         debug_printf (1, "\nsoup_uri_new (NULL)\n");
357         uri = soup_uri_new (NULL);
358         if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
359                 debug_printf (1, "  ERROR: soup_uri_new(NULL) returns valid URI?\n");
360                 errors++;
361         }
362
363         /* This implicitly also verifies that none of these methods g_warn */
364         if (soup_uri_get_scheme (uri) ||
365             soup_uri_get_user (uri) ||
366             soup_uri_get_password (uri) ||
367             soup_uri_get_host (uri) ||
368             soup_uri_get_port (uri) ||
369             soup_uri_get_path (uri) ||
370             soup_uri_get_query (uri) ||
371             soup_uri_get_fragment (uri)) {
372                 debug_printf (1, "  ERROR: soup_uri_new(NULL) returns non-empty URI?\n");
373                 errors++;
374         }
375
376         expect_warning = TRUE;
377         uri2 = soup_uri_new_with_base (uri, "/path");
378         if (uri2 || expect_warning) {
379                 debug_printf (1, "  ERROR: soup_uri_new_with_base didn't fail on NULL URI?\n");
380                 errors++;
381                 expect_warning = FALSE;
382         }
383
384         expect_warning = TRUE;
385         uri_string = soup_uri_to_string (uri, FALSE);
386         if (expect_warning) {
387                 debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on NULL URI?\n");
388                 errors++;
389                 expect_warning = FALSE;
390         } else if (*uri_string) {
391                 debug_printf (1, "  ERROR: soup_uri_to_string on NULL URI returned '%s'\n",
392                               uri_string);
393                 errors++;
394         }
395         g_free (uri_string);
396
397         soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
398         if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
399                 debug_printf (1, "  ERROR: setting scheme on NULL URI makes it valid?\n");
400                 errors++;
401         }
402
403         expect_warning = TRUE;
404         uri_string = soup_uri_to_string (uri, FALSE);
405         if (expect_warning) {
406                 debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on scheme-only URI?\n");
407                 errors++;
408                 expect_warning = FALSE;
409         } else if (strcmp (uri_string, "http:") != 0) {
410                 debug_printf (1, "  ERROR: soup_uri_to_string returned '%s' instead of 'http:'\n",
411                               uri_string);
412                 errors++;
413         }
414         g_free (uri_string);
415
416         soup_uri_set_host (uri, "localhost");
417         if (SOUP_URI_IS_VALID (uri)) {
418                 debug_printf (1, "  ERROR: setting scheme+host on NULL URI makes it valid?\n");
419                 errors++;
420         }
421         if (SOUP_URI_VALID_FOR_HTTP (uri)) {
422                 debug_printf (1, "  ERROR: setting scheme+host on NULL URI makes it valid for http?\n");
423                 errors++;
424         }
425
426         expect_warning = TRUE;
427         uri_string = soup_uri_to_string (uri, FALSE);
428         if (expect_warning) {
429                 debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on scheme+host URI?\n");
430                 errors++;
431                 expect_warning = FALSE;
432         } else if (strcmp (uri_string, "http://localhost/") != 0) {
433                 debug_printf (1, "  ERROR: soup_uri_to_string with NULL path returned '%s' instead of 'http://localhost/'\n",
434                               uri_string);
435                 errors++;
436         }
437         g_free (uri_string);
438
439         expect_warning = TRUE;
440         uri2 = soup_uri_new_with_base (uri, "/path");
441         if (expect_warning) {
442                 debug_printf (1, "  ERROR: soup_uri_new_with_base didn't warn on NULL+scheme URI?\n");
443                 errors++;
444                 expect_warning = FALSE;
445         } else if (!uri2) {
446                 debug_printf (1, "  ERROR: soup_uri_new_with_base didn't fix path on NULL+scheme URI\n");
447                 errors++;
448         }
449
450         if (uri2) {
451                 uri_string = soup_uri_to_string (uri2, FALSE);
452                 if (!uri_string) {
453                         debug_printf (1, "  ERROR: soup_uri_to_string failed on uri2?\n");
454                         errors++;
455                 } else if (strcmp (uri_string, "http://localhost/path") != 0) {
456                         debug_printf (1, "  ERROR: soup_uri_to_string returned '%s' instead of 'http://localhost/path'\n",
457                                       uri_string);
458                         errors++;
459                 }
460                 g_free (uri_string);
461                 soup_uri_free (uri2);
462         }
463
464         expect_warning = TRUE;
465         soup_uri_set_path (uri, NULL);
466         if (expect_warning) {
467                 debug_printf (1, "  ERROR: setting path to NULL doesn't warn\n");
468                 errors++;
469                 expect_warning = FALSE;
470         }
471         if (!uri->path || *uri->path) {
472                 debug_printf (1, "  ERROR: setting path to NULL != \"\"\n");
473                 errors++;
474                 soup_uri_set_path (uri, "");
475         }
476
477         uri_string = soup_uri_to_string (uri, FALSE);
478         if (!uri_string) {
479                 debug_printf (1, "  ERROR: soup_uri_to_string failed on complete URI?\n");
480                 errors++;
481         } else if (strcmp (uri_string, "http://localhost/") != 0) {
482                 debug_printf (1, "  ERROR: soup_uri_to_string with empty path returned '%s' instead of 'http://localhost/'\n",
483                               uri_string);
484                 errors++;
485         }
486         g_free (uri_string);
487
488         if (!SOUP_URI_IS_VALID (uri)) {
489                 debug_printf (1, "  ERROR: setting scheme+path on NULL URI doesn't make it valid?\n");
490                 errors++;
491         }
492         if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
493                 debug_printf (1, "  ERROR: setting scheme+host+path on NULL URI doesn't make it valid for http?\n");
494                 errors++;
495         }
496
497         soup_uri_free (uri);
498 }
499
500 static struct {
501         const char *uri_string, *unescape_extra, *result;
502 } normalization_tests[] = {
503         { "fo%6fbar",         NULL, "foobar" },
504         { "foo%2fbar",        NULL, "foo%2fbar" },
505         { "foo%2Fbar",        NULL, "foo%2Fbar" },
506         { "foo%2fbar",        "/",  "foo/bar" },
507         { "foo bar",          NULL, "foo%20bar" },
508         { "foo bar",          " ",  "foo bar" },
509         { "fo\xc3\xb6" "bar", NULL, "fo%C3%B6bar" },
510         { "fo\xc3\xb6 bar",   " ",  "fo%C3%B6 bar" }
511 };
512 static int num_normalization_tests = G_N_ELEMENTS (normalization_tests);
513
514 static void
515 do_normalization_tests (void)
516 {
517         char *normalized;
518         int i;
519
520         debug_printf (1, "\nsoup_uri_normalize\n");
521
522         for (i = 0; i < num_normalization_tests; i++) {
523                 if (normalization_tests[i].unescape_extra) {
524                         debug_printf (1, "<%s> unescaping <%s> => <%s>: ",
525                                       normalization_tests[i].uri_string,
526                                       normalization_tests[i].unescape_extra,
527                                       normalization_tests[i].result);
528                 } else {
529                         debug_printf (1, "<%s> => <%s>: ",
530                                       normalization_tests[i].uri_string,
531                                       normalization_tests[i].result);
532                 }
533
534                 normalized = soup_uri_normalize (normalization_tests[i].uri_string,
535                                                  normalization_tests[i].unescape_extra);
536
537                 if (!strcmp (normalized, normalization_tests[i].result))
538                         debug_printf (1, "OK\n");
539                 else {
540                         debug_printf (1, "NO, got <%s>\n", normalized);
541                         errors++;
542                 }
543                 g_free (normalized);
544         }
545 }
546
547 int
548 main (int argc, char **argv)
549 {
550         SoupURI *base_uri, *uri1, *uri2;
551         char *uri_string;
552         int i;
553
554         test_init (argc, argv, NULL);
555
556         debug_printf (1, "Absolute URI parsing\n");
557         for (i = 0; i < num_abs_tests; i++) {
558                 if (!do_uri (NULL, NULL, abs_tests[i].uri_string,
559                              abs_tests[i].result, &abs_tests[i].bits))
560                         errors++;
561         }
562
563         debug_printf (1, "\nRelative URI parsing\n");
564         base_uri = soup_uri_new (base);
565         if (!base_uri) {
566                 g_printerr ("Could not parse %s!\n", base);
567                 exit (1);
568         }
569
570         uri_string = soup_uri_to_string (base_uri, FALSE);
571         if (strcmp (uri_string, base) != 0) {
572                 g_printerr ("URI <%s> unparses to <%s>\n",
573                             base, uri_string);
574                 errors++;
575         }
576         g_free (uri_string);
577
578         for (i = 0; i < num_rel_tests; i++) {
579                 if (!do_uri (base_uri, base, rel_tests[i].uri_string,
580                              rel_tests[i].result, &rel_tests[i].bits))
581                         errors++;
582         }
583         soup_uri_free (base_uri);
584
585         debug_printf (1, "\nURI equality testing\n");
586         for (i = 0; i < num_eq_tests; i++) {
587                 uri1 = soup_uri_new (eq_tests[i].one);
588                 uri2 = soup_uri_new (eq_tests[i].two);
589                 debug_printf (1, "<%s> == <%s>? ", eq_tests[i].one, eq_tests[i].two);
590                 if (soup_uri_equal (uri1, uri2))
591                         debug_printf (1, "OK\n");
592                 else {
593                         debug_printf (1, "NO\n");
594                         debug_printf (1, "%s : %s : %s\n%s : %s : %s\n",
595                                       uri1->scheme, uri1->host, uri1->path,
596                                       uri2->scheme, uri2->host, uri2->path);
597                         errors++;
598                 }
599                 soup_uri_free (uri1);
600                 soup_uri_free (uri2);
601         }
602
603         do_soup_uri_null_tests ();
604         do_normalization_tests ();
605
606         test_cleanup ();
607         return errors != 0;
608 }