xref: /haiku/src/tests/kits/net/service/UrlTest.cpp (revision f4db7fdc68461d7d30abb6ae43fa762917963ce1)
1f38d4d45SAdrien Destugues /*
2f38d4d45SAdrien Destugues  * Copyright 2010, Christophe Huriaux
3f38d4d45SAdrien Destugues  * Copyright 2014, Haiku, inc.
4f38d4d45SAdrien Destugues  * Distributed under the terms of the MIT licence
5f38d4d45SAdrien Destugues  */
6f38d4d45SAdrien Destugues 
7f38d4d45SAdrien Destugues 
8f38d4d45SAdrien Destugues #include "UrlTest.h"
9f38d4d45SAdrien Destugues 
10f38d4d45SAdrien Destugues 
11f38d4d45SAdrien Destugues #include <cstdlib>
12f38d4d45SAdrien Destugues #include <cstring>
13f38d4d45SAdrien Destugues #include <cstdio>
14f38d4d45SAdrien Destugues 
15f38d4d45SAdrien Destugues #include <NetworkKit.h>
16f38d4d45SAdrien Destugues 
17f38d4d45SAdrien Destugues #include <cppunit/TestCaller.h>
18f38d4d45SAdrien Destugues #include <cppunit/TestSuite.h>
19f38d4d45SAdrien Destugues 
20f38d4d45SAdrien Destugues 
21f38d4d45SAdrien Destugues UrlTest::UrlTest()
22f38d4d45SAdrien Destugues {
23f38d4d45SAdrien Destugues }
24f38d4d45SAdrien Destugues 
25f38d4d45SAdrien Destugues 
26f38d4d45SAdrien Destugues UrlTest::~UrlTest()
27f38d4d45SAdrien Destugues {
28f38d4d45SAdrien Destugues }
29f38d4d45SAdrien Destugues 
30f38d4d45SAdrien Destugues 
31f38d4d45SAdrien Destugues // Test that parsing a valid URL and converting back to string doesn't alter it
32f38d4d45SAdrien Destugues void UrlTest::ParseTest()
33f38d4d45SAdrien Destugues {
34f38d4d45SAdrien Destugues 	uint8 testIndex;
35f38d4d45SAdrien Destugues 	BUrl testUrl;
36f38d4d45SAdrien Destugues 
37f38d4d45SAdrien Destugues 	const char* kTestLength[] =
38f38d4d45SAdrien Destugues 	{
39f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/path?query#fragment",
40f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/path?query#",
41f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/path?query",
42f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/path?",
43f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/path",
44f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com:80/",
45f38d4d45SAdrien Destugues 		"http://user:pass@www.foo.com",
46f38d4d45SAdrien Destugues 		"http://user:pass@",
47f38d4d45SAdrien Destugues 		"http://www.foo.com",
48f38d4d45SAdrien Destugues 		"http://",
49f38d4d45SAdrien Destugues 		"http:"
50f38d4d45SAdrien Destugues 	};
51f38d4d45SAdrien Destugues 
52f38d4d45SAdrien Destugues 	for (testIndex = 0; testIndex < sizeof(kTestLength) / sizeof(const char*);
53f38d4d45SAdrien Destugues 		testIndex++)
54f38d4d45SAdrien Destugues 	{
55f38d4d45SAdrien Destugues 		NextSubTest();
56f38d4d45SAdrien Destugues 
57f38d4d45SAdrien Destugues 		testUrl.SetUrlString(kTestLength[testIndex]);
58f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestLength[testIndex]),
59f38d4d45SAdrien Destugues 			testUrl.UrlString());
60f38d4d45SAdrien Destugues 	}
61f38d4d45SAdrien Destugues }
62f38d4d45SAdrien Destugues 
63f38d4d45SAdrien Destugues 
64f38d4d45SAdrien Destugues void UrlTest::TestIsValid()
65f38d4d45SAdrien Destugues {
66f38d4d45SAdrien Destugues 	BUrl url("http:");
67f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Created with a scheme but no hierarchical segment.",
68f38d4d45SAdrien Destugues 		!url.IsValid());
69f38d4d45SAdrien Destugues 
70f38d4d45SAdrien Destugues 	url.SetHost("<invalid>");
71*f4db7fdcSAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Set to an invalid host", !url.IsValid());
72f38d4d45SAdrien Destugues 
73f38d4d45SAdrien Destugues 	url.SetUrlString("");
74f38d4d45SAdrien Destugues 	url.SetProtocol("\t \n");
75f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Set a protocol with whitespace", !url.IsValid());
76f38d4d45SAdrien Destugues 	url.SetProtocol("123");
77f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Set an all-digits protocol", !url.IsValid());
78f38d4d45SAdrien Destugues 
79f38d4d45SAdrien Destugues 	url.SetUserName("user");
80f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Retain invalid state on user change",
81f38d4d45SAdrien Destugues 		!url.IsValid());
82f38d4d45SAdrien Destugues 	url.SetPassword("pass");
83f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Retain invalid state on password change",
84f38d4d45SAdrien Destugues 		!url.IsValid());
85f38d4d45SAdrien Destugues 
86f38d4d45SAdrien Destugues 	url.SetProtocol("http");
87f38d4d45SAdrien Destugues 	url.SetFragment("fragment");
88f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Only protocol and fragment are set",
89f38d4d45SAdrien Destugues 		!url.IsValid());
90f38d4d45SAdrien Destugues 	url.SetFragment("fragment");
91f38d4d45SAdrien Destugues 	url.SetProtocol("http");
92f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_MESSAGE("Only protocol and fragment are set",
93f38d4d45SAdrien Destugues 		!url.IsValid());
94f38d4d45SAdrien Destugues }
95f38d4d45SAdrien Destugues 
96f38d4d45SAdrien Destugues 
97f38d4d45SAdrien Destugues void UrlTest::TestGettersSetters()
98f38d4d45SAdrien Destugues {
99f38d4d45SAdrien Destugues 	BUrl url;
100f38d4d45SAdrien Destugues 	url.SetProtocol("http");
101f38d4d45SAdrien Destugues 	url.SetUserName("user");
102f38d4d45SAdrien Destugues 	url.SetPassword("password");
103f38d4d45SAdrien Destugues 	url.SetHost("example.com");
104f38d4d45SAdrien Destugues 	url.SetPort(8080);
105f38d4d45SAdrien Destugues 	url.SetPath("/path");
106f38d4d45SAdrien Destugues 	url.SetRequest("query=value");
107f38d4d45SAdrien Destugues 	url.SetFragment("fragment");
108f38d4d45SAdrien Destugues 
109f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("http"), url.Protocol());
110f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("user"), url.UserName());
111f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("password"), url.Password());
112f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("user:password"), url.UserInfo());
113f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("example.com"), url.Host());
114f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("user:password@example.com:8080"),
115f38d4d45SAdrien Destugues 		url.Authority());
116f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(8080, url.Port());
117f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("/path"), url.Path());
118f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("query=value"), url.Request());
119f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("fragment"), url.Fragment());
120f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString(
121f38d4d45SAdrien Destugues 			"http://user:password@example.com:8080/path?query=value#fragment"),
122f38d4d45SAdrien Destugues 		url.UrlString());
123f38d4d45SAdrien Destugues }
124f38d4d45SAdrien Destugues 
125f38d4d45SAdrien Destugues 
126f38d4d45SAdrien Destugues void UrlTest::TestNullity()
127f38d4d45SAdrien Destugues {
128f38d4d45SAdrien Destugues 	BUrl url;
129f38d4d45SAdrien Destugues 	url.SetProtocol("http");
130f38d4d45SAdrien Destugues 	url.SetHost("example.com");
131f38d4d45SAdrien Destugues 
132f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(url.HasAuthority());
133f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(url.HasHost());
134f38d4d45SAdrien Destugues 
135f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasUserName());
136f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasPassword());
137f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasUserInfo());
138f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasPort());
139f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasPath());
140f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasRequest());
141f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(!url.HasFragment());
142f38d4d45SAdrien Destugues }
143f38d4d45SAdrien Destugues 
144f38d4d45SAdrien Destugues 
145f38d4d45SAdrien Destugues void UrlTest::TestCopy()
146f38d4d45SAdrien Destugues {
147f38d4d45SAdrien Destugues 	BUrl url1("http://example.com");
148f38d4d45SAdrien Destugues 	BUrl url2(url1);
149f38d4d45SAdrien Destugues 
150f38d4d45SAdrien Destugues 	url2.SetHost("www.example.com");
151f38d4d45SAdrien Destugues 
152f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("www.example.com"), url2.Host());
153f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("http://www.example.com"), url2.UrlString());
154f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("example.com"), url1.Host());
155f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("http://example.com"), url1.UrlString());
156f38d4d45SAdrien Destugues }
157f38d4d45SAdrien Destugues 
158f38d4d45SAdrien Destugues 
159f38d4d45SAdrien Destugues typedef struct
160f38d4d45SAdrien Destugues {
161f38d4d45SAdrien Destugues 	const char* url;
162f38d4d45SAdrien Destugues 
163f38d4d45SAdrien Destugues 	struct
164f38d4d45SAdrien Destugues 	{
165f38d4d45SAdrien Destugues 		const char* protocol;
166f38d4d45SAdrien Destugues 		const char* userName;
167f38d4d45SAdrien Destugues 		const char* password;
168f38d4d45SAdrien Destugues 		const char* host;
169f38d4d45SAdrien Destugues 		int16		port;
170f38d4d45SAdrien Destugues 		const char* path;
171f38d4d45SAdrien Destugues 		const char* request;
172f38d4d45SAdrien Destugues 		const char* fragment;
173f38d4d45SAdrien Destugues 	} expected;
174f38d4d45SAdrien Destugues } ExplodeTest;
175f38d4d45SAdrien Destugues 
176f38d4d45SAdrien Destugues 
177f38d4d45SAdrien Destugues const ExplodeTest	kTestExplode[] =
178f38d4d45SAdrien Destugues 	//  Url
179f38d4d45SAdrien Destugues 	//       Protocol     User  Password  Hostname  Port     Path    Request      Fragment
180f38d4d45SAdrien Destugues 	//       -------- --------- --------- --------- ---- ---------- ---------- ------------
181f38d4d45SAdrien Destugues 	{
182f38d4d45SAdrien Destugues 		{ "http://user:pass@host:80/path?query#fragment",
183f38d4d45SAdrien Destugues 			{ "http",   "user",   "pass",   "host",	 80,   "/path",	  "query",   "fragment" } },
184f38d4d45SAdrien Destugues 		{ "http://www.host.tld/path?query#fragment",
185f38d4d45SAdrien Destugues 			{ "http",   "",        "", "www.host.tld",0,   "/path",	  "query",   "fragment" } },
186f38d4d45SAdrien Destugues 		{ "",
187f38d4d45SAdrien Destugues 			{ "",       "",        "", "",            0,   "",        "",        ""} },
188f38d4d45SAdrien Destugues 		{ "mailto:John.Doe@example.com",
189f38d4d45SAdrien Destugues 			{ "mailto", "",        "", "",            0,   "John.Doe@example.com", "", "" } },
190f38d4d45SAdrien Destugues 		{ "mailto:?to=addr1@an.example,addr2@an.example",
191f38d4d45SAdrien Destugues 			{ "mailto", "",        "", "",            0,   "",        "to=addr1@an.example,addr2@an.example", "" } },
192f38d4d45SAdrien Destugues 		{ "urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
193043178a0SAdrien Destugues 			{ "urn",    "",        "", "",            0,   "oasis:names:specification:docbook:dtd:xml:4.1.2", "", "" } },
194043178a0SAdrien Destugues 		{ "http://www.goodsearch.com/login?return_path=/",
195043178a0SAdrien Destugues 			{ "http",   "",        "", "www.goodsearch.com", 0, "/login", "return_path=/", "" } },
196*f4db7fdcSAdrien Destugues 		{ "ldap://[2001:db8::7]:389/c=GB?objectClass?one",
197043178a0SAdrien Destugues 			{ "ldap",   "",        "", "[2001:db8::7]",389,"/c=GB",   "objectClass?one", "" } },
198*f4db7fdcSAdrien Destugues 		{ "ldap://[2001:db8::7]/c=GB?objectClass?one",
199*f4db7fdcSAdrien Destugues 			{ "ldap",   "",        "", "[2001:db8::7]",0,  "/c=GB",   "objectClass?one", "" } },
200043178a0SAdrien Destugues 		{ "HTTP://example.com.:80/%70a%74%68?a=%31#1%323",
201*f4db7fdcSAdrien Destugues 			{ "HTTP",   "",        "", "example.com.",80,  "/%70a%74%68","a=%31","1%323"} },
202*f4db7fdcSAdrien Destugues 		{ "/boot/home/Desktop/index.html",
203*f4db7fdcSAdrien Destugues 			{ "",   "",            "", "",             0,  "/boot/home/Desktop/index.html","",""} },
204*f4db7fdcSAdrien Destugues 		{ "//remote.host/boot/home/Desktop",
205*f4db7fdcSAdrien Destugues 			{ "",   "",            "", "remote.host",  0,  "/boot/home/Desktop","",""} }
206f38d4d45SAdrien Destugues 	};
207f38d4d45SAdrien Destugues 
208f38d4d45SAdrien Destugues void UrlTest::ExplodeImplodeTest()
209f38d4d45SAdrien Destugues {
210f38d4d45SAdrien Destugues 	uint8 testIndex;
211f38d4d45SAdrien Destugues 	BUrl testUrl;
212f38d4d45SAdrien Destugues 
213f38d4d45SAdrien Destugues 	for (testIndex = 0; testIndex < (sizeof(kTestExplode) / sizeof(ExplodeTest)); testIndex++)
214f38d4d45SAdrien Destugues 	{
215f38d4d45SAdrien Destugues 		NextSubTest();
216f38d4d45SAdrien Destugues 		testUrl.SetUrlString(kTestExplode[testIndex].url);
217f38d4d45SAdrien Destugues 
218f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].url),
219f38d4d45SAdrien Destugues 			BString(testUrl.UrlString()));
220f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.protocol),
221f38d4d45SAdrien Destugues 			BString(testUrl.Protocol()));
222f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.userName),
223f38d4d45SAdrien Destugues 			BString(testUrl.UserName()));
224f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.password),
225f38d4d45SAdrien Destugues 			BString(testUrl.Password()));
226f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.host),
227f38d4d45SAdrien Destugues 			BString(testUrl.Host()));
228f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(kTestExplode[testIndex].expected.port,
229f38d4d45SAdrien Destugues 			testUrl.Port());
230f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.path),
231f38d4d45SAdrien Destugues 			BString(testUrl.Path()));
232f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.request),
233f38d4d45SAdrien Destugues 			BString(testUrl.Request()));
234f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(BString(kTestExplode[testIndex].expected.fragment),
235f38d4d45SAdrien Destugues 			BString(testUrl.Fragment()));
236f38d4d45SAdrien Destugues 	}
237f38d4d45SAdrien Destugues }
238f38d4d45SAdrien Destugues 
239f38d4d45SAdrien Destugues 
240f38d4d45SAdrien Destugues void
241f38d4d45SAdrien Destugues UrlTest::PathOnly()
242f38d4d45SAdrien Destugues {
243f38d4d45SAdrien Destugues 	BUrl test = "lol";
244f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT(test.HasPath());
245f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("lol"), test.Path());
246f38d4d45SAdrien Destugues 	CPPUNIT_ASSERT_EQUAL(BString("lol"), test.UrlString());
247f38d4d45SAdrien Destugues }
248f38d4d45SAdrien Destugues 
249f38d4d45SAdrien Destugues 
250f38d4d45SAdrien Destugues void
251f38d4d45SAdrien Destugues UrlTest::RelativeUriTest()
252f38d4d45SAdrien Destugues {
253f38d4d45SAdrien Destugues 	// http://skew.org/uri/uri%5Ftests.html
254f38d4d45SAdrien Destugues 	struct RelativeUrl {
255f38d4d45SAdrien Destugues 		const char* base;
256f38d4d45SAdrien Destugues 		const char* relative;
257f38d4d45SAdrien Destugues 		const char* absolute;
258f38d4d45SAdrien Destugues 	};
259f38d4d45SAdrien Destugues 
260f38d4d45SAdrien Destugues 	const RelativeUrl tests[] = {
2614359643eSAdrien Destugues 		// The port must be preserved
2624359643eSAdrien Destugues 		{"http://host:81/",		"/path",				"http://host:81/path"},
2634359643eSAdrien Destugues 
2644359643eSAdrien Destugues 		// Tests from http://skew.org/uri/uri_tests.html
265f38d4d45SAdrien Destugues 		{"http://example.com/path?query#frag", "",
266f38d4d45SAdrien Destugues 			"http://example.com/path?query"},
2674359643eSAdrien Destugues 			// The fragment must be dropped when changing the path, but the
2684359643eSAdrien Destugues 			// query must be preserved
269f38d4d45SAdrien Destugues 		{"foo:a/b",				"../c",					"foo:/c"},
270f38d4d45SAdrien Destugues 			// foo:c would be more intuitive, and is what skew.org tests.
271f38d4d45SAdrien Destugues 			// However, foo:/c is what the RFC says we should get.
272f38d4d45SAdrien Destugues 		{"foo:a",				"foo:.",				"foo:"},
273f38d4d45SAdrien Destugues 		{"zz:abc",				"/foo/../../../bar",	"zz:/bar"},
274f38d4d45SAdrien Destugues 		{"zz:abc",				"/foo/../bar",			"zz:/bar"},
275f38d4d45SAdrien Destugues 		{"zz:abc",				"foo/../../../bar",		"zz:/bar"},
276f38d4d45SAdrien Destugues 			// zz:bar would be more intuitive, ...
277f38d4d45SAdrien Destugues 		{"zz:abc",				"zz:.",					"zz:"},
278f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/.",					"http://a/"},
279f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/.foo",				"http://a/.foo"},
280f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	".foo",					"http://a/b/c/.foo"},
281f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g:h",					"g:h"},
282f38d4d45SAdrien Destugues 
283f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g:h",					"g:h"},
284f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g",					"http://a/b/c/g"},
285f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"./g",					"http://a/b/c/g"},
286f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g/",					"http://a/b/c/g/"},
287f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/g",					"http://a/g"},
288f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"//g",					"http://g"},
289f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"?y",					"http://a/b/c/d;p?y"},
290f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g?y",					"http://a/b/c/g?y"},
291f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"#s",					"http://a/b/c/d;p?q#s"},
292f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g#s",					"http://a/b/c/g#s"},
293f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g?y#s",				"http://a/b/c/g?y#s"},
294f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	";x",					"http://a/b/c/;x"},
295f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g;x",					"http://a/b/c/g;x"},
296f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g;x?y#s",				"http://a/b/c/g;x?y#s"},
297f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"",						"http://a/b/c/d;p?q"},
298f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	".",					"http://a/b/c/"},
299f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"./",					"http://a/b/c/"},
300f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"..",					"http://a/b/"},
301f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../",					"http://a/b/"},
302f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../g",					"http://a/b/g"},
303f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../..",				"http://a/"},
304f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../../",				"http://a/"},
305f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../../g",				"http://a/g"},
306f38d4d45SAdrien Destugues 
307f38d4d45SAdrien Destugues 		// Parsers must be careful in handling cases where there are more
308f38d4d45SAdrien Destugues 		// relative path ".." segments than there are hierarchical levels in the
309f38d4d45SAdrien Destugues 		// base URI's path. Note that the ".." syntax cannot be used to change
310f38d4d45SAdrien Destugues 		// the authority component of a URI.
311f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../../../g",			"http://a/g"},
312f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"../../../../g",		"http://a/g"},
313f38d4d45SAdrien Destugues 
314f38d4d45SAdrien Destugues 		// Similarly, parsers must remove the dot-segments "." and ".." when
315f38d4d45SAdrien Destugues 		// they are complete components of a path, but not when they are only
316f38d4d45SAdrien Destugues 		// part of a segment.
317f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/./g",					"http://a/g"},
318f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/../g",				"http://a/g"},
319f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g.",					"http://a/b/c/g."},
320f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	".g",					"http://a/b/c/.g"},
321f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g..",					"http://a/b/c/g.."},
322f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"..g",					"http://a/b/c/..g"},
323f38d4d45SAdrien Destugues 
324f38d4d45SAdrien Destugues 		// Less likely are cases where the relative URI reference uses
325f38d4d45SAdrien Destugues 		// unnecessary or nonsensical forms of the "." and ".." complete path
326f38d4d45SAdrien Destugues 		// segments.
327f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"./../g",				"http://a/b/g"},
328f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"./g/.",				"http://a/b/c/g/"},
329f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g/./h",				"http://a/b/c/g/h"},
330f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g/../h",				"http://a/b/c/h"},
331f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g;x=1/./y",			"http://a/b/c/g;x=1/y"},
332f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g;x=1/../y",			"http://a/b/c/y"},
333f38d4d45SAdrien Destugues 
334f38d4d45SAdrien Destugues 		// Some applications fail to separate the reference's query and/or
335f38d4d45SAdrien Destugues 		// fragment components from a relative path before merging it with the
336f38d4d45SAdrien Destugues 		// base path and removing dot-segments. This error is rarely noticed,
337f38d4d45SAdrien Destugues 		// since typical usage of a fragment never includes the hierarchy ("/")
338f38d4d45SAdrien Destugues 		// character, and the query component is not normally used within
339f38d4d45SAdrien Destugues 		// relative references.
340f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g?y/./x",			"http://a/b/c/g?y/./x"},
341f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g?y/../x",			"http://a/b/c/g?y/../x"},
342f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g#s/./x",			"http://a/b/c/g#s/./x"},
343f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"g#s/../x",			"http://a/b/c/g#s/../x"},
344f38d4d45SAdrien Destugues 
345f38d4d45SAdrien Destugues 		// Some parsers allow the scheme name to be present in a relative URI
346f38d4d45SAdrien Destugues 		// reference if it is the same as the base URI scheme. This is
347f38d4d45SAdrien Destugues 		// considered to be a loophole in prior specifications of partial URI
348f38d4d45SAdrien Destugues 		// [RFC1630]. Its use should be avoided, but is allowed for backward
349f38d4d45SAdrien Destugues 		// compatibility.
350f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"http:g",			"http:g"},
351f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"http:",			"http:"},
352f38d4d45SAdrien Destugues 
353f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"./g:h",			"http://a/b/c/g:h"},
354f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q",	"/a/b/c/./../../g",	"http://a/a/g"},
355f38d4d45SAdrien Destugues 
356f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g",			"http://a/b/c/g"},
357f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"./g",			"http://a/b/c/g"},
358f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g/",			"http://a/b/c/g/"},
359f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"/g",			"http://a/g"},
360f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"//g",			"http://g"},
361f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"?y",			"http://a/b/c/d;p?y"},
362f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g?y",			"http://a/b/c/g?y"},
363f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g?y/./x",		"http://a/b/c/g?y/./x"},
364f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g?y/../x",		"http://a/b/c/g?y/../x"},
365f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g#s",			"http://a/b/c/g#s"},
366f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g#s/./x",		"http://a/b/c/g#s/./x"},
367f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"g#s/../x",		"http://a/b/c/g#s/../x"},
368f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"./",			"http://a/b/c/"},
369f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"../",			"http://a/b/"},
370f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"../g",			"http://a/b/g"},
371f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"../../",		"http://a/"},
372f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p?q=1/2",	"../../g",		"http://a/g"},
373f38d4d45SAdrien Destugues 
374f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"g",			"http://a/b/c/d;p=1/g"},
375f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"./g",			"http://a/b/c/d;p=1/g"},
376f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"g/",			"http://a/b/c/d;p=1/g/"},
377f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"g?y",			"http://a/b/c/d;p=1/g?y"},
378f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	";x",			"http://a/b/c/d;p=1/;x"},
379f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"g;x",			"http://a/b/c/d;p=1/g;x"},
380f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q", "g;x=1/./y", "http://a/b/c/d;p=1/g;x=1/y"},
381f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"g;x=1/../y",	"http://a/b/c/d;p=1/y"},
382f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"./",			"http://a/b/c/d;p=1/"},
383f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"../",			"http://a/b/c/"},
384f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"../g",			"http://a/b/c/g"},
385f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"../../",		"http://a/b/"},
386f38d4d45SAdrien Destugues 		{"http://a/b/c/d;p=1/2?q",	"../../g",		"http://a/b/g"},
387f38d4d45SAdrien Destugues 
388f38d4d45SAdrien Destugues 		// Empty host and directory
389f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"g:h",					"g:h"},
390f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"g",					"fred:///s//a/b/g"},
391f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"./g",					"fred:///s//a/b/g"},
392f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"g/",					"fred:///s//a/b/g/"},
393f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"/g",					"fred:///g"},
394f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"//g",					"fred://g"},
395f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"//g/x",				"fred://g/x"},
396f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"///g",					"fred:///g"},
397f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"./",					"fred:///s//a/b/"},
398f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../",					"fred:///s//a/"},
399f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../g",					"fred:///s//a/g"},
400f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../..",				"fred:///s//"},
401f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../../g",				"fred:///s//g"},
402f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../../../g",			"fred:///s/g"},
403f38d4d45SAdrien Destugues 		{"fred:///s//a/b/c",	"../../../g",			"fred:///s/g"},
404f38d4d45SAdrien Destugues 
405f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"g:h",					"g:h"},
406f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"g",					"http:///s//a/b/g"},
407f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"./g",					"http:///s//a/b/g"},
408f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"g/",					"http:///s//a/b/g/"},
409f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"/g",					"http:///g"},
410f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"//g",					"http://g"},
411f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"//g/x",				"http://g/x"},
412f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"///g",					"http:///g"},
413f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"./",					"http:///s//a/b/"},
414f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../",					"http:///s//a/"},
415f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../g",					"http:///s//a/g"},
416f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../..",				"http:///s//"},
417f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../../g",				"http:///s//g"},
418f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../../../g",			"http:///s/g"},
419f38d4d45SAdrien Destugues 		{"http:///s//a/b/c",	"../../../g",			"http:///s/g"},
420f38d4d45SAdrien Destugues 
421f38d4d45SAdrien Destugues 		{"foo:xyz",				"bar:abc",				"bar:abc"},
422f38d4d45SAdrien Destugues 		{"http://example/x/y/z","../abc",				"http://example/x/abc"},
423f38d4d45SAdrien Destugues 		{"http://example2/x/y/z","http://example/x/abc","http://example/x/abc"},
424f38d4d45SAdrien Destugues 		{"http://ex/x/y/z",		"../r",					"http://ex/x/r"},
425f38d4d45SAdrien Destugues 		{"http://ex/x/y",		"q/r",					"http://ex/x/q/r"},
426f38d4d45SAdrien Destugues 		{"http://ex/x/y",		"q/r#s",				"http://ex/x/q/r#s"},
427f38d4d45SAdrien Destugues 		{"http://ex/x/y",		"q/r#s/t",				"http://ex/x/q/r#s/t"},
428f38d4d45SAdrien Destugues 		{"http://ex/x/y",		"ftp://ex/x/q/r",		"ftp://ex/x/q/r"},
429f38d4d45SAdrien Destugues 		{"http://ex/x/y",		"",						"http://ex/x/y"},
430f38d4d45SAdrien Destugues 		{"http://ex/x/y/",		"",						"http://ex/x/y/"},
431f38d4d45SAdrien Destugues 		{"http://ex/x/y/pdq",	"",						"http://ex/x/y/pdq"},
432f38d4d45SAdrien Destugues 		{"http://ex/x/y/",		"z/",					"http://ex/x/y/z/"},
433f38d4d45SAdrien Destugues 
434f38d4d45SAdrien Destugues 		{"file:/swap/test/animal.rdf", "#Animal",
435f38d4d45SAdrien Destugues 			"file:/swap/test/animal.rdf#Animal"},
436f38d4d45SAdrien Destugues 		{"file:/e/x/y/z",		"../abc",				"file:/e/x/abc"},
437f38d4d45SAdrien Destugues 		{"file:/example2/x/y/z","/example/x/abc",		"file:/example/x/abc"},
438f38d4d45SAdrien Destugues 		{"file:/e/x/y/z",		"../r",					"file:/e/x/r"},
439f38d4d45SAdrien Destugues 		{"file:/e/x/y/z",		"/r",					"file:/r"},
440f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"q/r",					"file:/e/x/q/r"},
441f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"q/r#s",				"file:/e/x/q/r#s"},
442f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"q/r#",					"file:/e/x/q/r#"},
443f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"q/r#s/t",				"file:/e/x/q/r#s/t"},
444f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"ftp://ex/x/q/r",		"ftp://ex/x/q/r"},
445f38d4d45SAdrien Destugues 		{"file:/e/x/y",			"",						"file:/e/x/y"},
446f38d4d45SAdrien Destugues 		{"file:/e/x/y/",		"",						"file:/e/x/y/"},
447f38d4d45SAdrien Destugues 		{"file:/e/x/y/pdq",		"",						"file:/e/x/y/pdq"},
448f38d4d45SAdrien Destugues 		{"file:/e/x/y/",		"z/",					"file:/e/x/y/z/"},
449f38d4d45SAdrien Destugues 		{"file:/devel/WWW/2000/10/swap/test/reluri-1.n3",
450f38d4d45SAdrien Destugues 			"file://meetings.example.com/cal#m1",
451f38d4d45SAdrien Destugues 			"file://meetings.example.com/cal#m1"},
452f38d4d45SAdrien Destugues 		{"file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3",
453f38d4d45SAdrien Destugues 			"file://meetings.example.com/cal#m1",
454f38d4d45SAdrien Destugues 			"file://meetings.example.com/cal#m1"},
455f38d4d45SAdrien Destugues 		{"file:/some/dir/foo",		"./#blort",		"file:/some/dir/#blort"},
456f38d4d45SAdrien Destugues 		{"file:/some/dir/foo",		"./#",			"file:/some/dir/#"},
457f38d4d45SAdrien Destugues 
458f38d4d45SAdrien Destugues 		{"http://example/x/abc.efg", "./",			"http://example/x/"},
459f38d4d45SAdrien Destugues 		{"http://example2/x/y/z", "//example/x/abc","http://example/x/abc"},
460f38d4d45SAdrien Destugues 		{"http://ex/x/y/z",			"/r",			"http://ex/r"},
461f38d4d45SAdrien Destugues 		{"http://ex/x/y",			"./q:r",		"http://ex/x/q:r"},
462f38d4d45SAdrien Destugues 		{"http://ex/x/y",			"./p=q:r",		"http://ex/x/p=q:r"},
463f38d4d45SAdrien Destugues 		{"http://ex/x/y?pp/qq",		"?pp/rr",		"http://ex/x/y?pp/rr"},
464f38d4d45SAdrien Destugues 		{"http://ex/x/y?pp/qq",		"y/z",			"http://ex/x/y/z"},
465f38d4d45SAdrien Destugues 
466f38d4d45SAdrien Destugues 		{"mailto:local", "local/qual@domain.org#frag",
467f38d4d45SAdrien Destugues 			"mailto:local/qual@domain.org#frag"},
468f38d4d45SAdrien Destugues 		{"mailto:local/qual1@domain1.org", "more/qual2@domain2.org#frag",
469f38d4d45SAdrien Destugues 			"mailto:local/more/qual2@domain2.org#frag"},
470f38d4d45SAdrien Destugues 
471f38d4d45SAdrien Destugues 		{"http://ex/x/y?q",		"y?q",			"http://ex/x/y?q"},
472f38d4d45SAdrien Destugues 		{"http://ex?p",			"x/y?q",		"http://ex/x/y?q"},
473f38d4d45SAdrien Destugues 		{"foo:a/b",				"c/d",			"foo:a/c/d"},
474f38d4d45SAdrien Destugues 		{"foo:a/b",				"/c/d",			"foo:/c/d"},
475f38d4d45SAdrien Destugues 		{"foo:a/b?c#d",			"",				"foo:a/b?c"},
476f38d4d45SAdrien Destugues 		{"foo:a",				"b/c",			"foo:b/c"},
477f38d4d45SAdrien Destugues 		{"foo:/a/y/z",			"../b/c",		"foo:/a/b/c"},
478f38d4d45SAdrien Destugues 		{"foo:a",				"./b/c",		"foo:b/c"},
479f38d4d45SAdrien Destugues 		{"foo:a",				"/./b/c",		"foo:/b/c"},
480f38d4d45SAdrien Destugues 		{"foo://a//b/c",		"../../d",		"foo://a/d"},
481f38d4d45SAdrien Destugues 		{"foo:a",				".",			"foo:"},
482f38d4d45SAdrien Destugues 		{"foo:a",				"..",			"foo:"},
483f38d4d45SAdrien Destugues 
484f38d4d45SAdrien Destugues 		{"http://example/x/y%2Fz", "abc",			"http://example/x/abc"},
485f38d4d45SAdrien Destugues 		{"http://example/a/x/y/z", "../../x%2Fabc", "http://example/a/x%2Fabc"},
486f38d4d45SAdrien Destugues 		{"http://example/a/x/y%2Fz", "../x%2Fabc", "http://example/a/x%2Fabc"},
487f38d4d45SAdrien Destugues 		{"http://example/x%2Fy/z", "abc", "http://example/x%2Fy/abc"},
488f38d4d45SAdrien Destugues 		{"http://ex/x/y", "q%3Ar", "http://ex/x/q%3Ar"},
489f38d4d45SAdrien Destugues 		{"http://example/x/y%2Fz", "/x%2Fabc", "http://example/x%2Fabc"},
490f38d4d45SAdrien Destugues 		{"http://example/x/y/z", "/x%2Fabc", "http://example/x%2Fabc"},
491f38d4d45SAdrien Destugues 
492f38d4d45SAdrien Destugues 		{"mailto:local1@domain1?query1", "local2@domain2",
493f38d4d45SAdrien Destugues 			"mailto:local2@domain2"},
494f38d4d45SAdrien Destugues 		{"mailto:local1@domain1", "local2@domain2?query2",
495f38d4d45SAdrien Destugues 			"mailto:local2@domain2?query2"},
496f38d4d45SAdrien Destugues 		{"mailto:local1@domain1?query1", "local2@domain2?query2",
497f38d4d45SAdrien Destugues 			"mailto:local2@domain2?query2"},
498f38d4d45SAdrien Destugues 		{"mailto:local@domain?query1", "?query2",
499f38d4d45SAdrien Destugues 			"mailto:local@domain?query2"},
500f38d4d45SAdrien Destugues 		{"mailto:?query1", "local2@domain2?query2",
501f38d4d45SAdrien Destugues 			"mailto:local2@domain2?query2"},
502f38d4d45SAdrien Destugues 		{"mailto:local1@domain1?query1", "?query2",
503f38d4d45SAdrien Destugues 			"mailto:local1@domain1?query2"},
504f38d4d45SAdrien Destugues 
505f38d4d45SAdrien Destugues 		{"foo:bar", "http://example/a/b?c/../d", "http://example/a/b?c/../d"},
506f38d4d45SAdrien Destugues 		{"foo:bar", "http://example/a/b#c/../d", "http://example/a/b#c/../d"},
507f38d4d45SAdrien Destugues 		{"http://example.org/base/uri", "http:this", "http:this"},
508f38d4d45SAdrien Destugues 		{"http:base", "http:this", "http:this"},
509f38d4d45SAdrien Destugues 		{"f:/a", ".//g", "f://g"},
510f38d4d45SAdrien Destugues 		{"f://example.org/base/a", "b/c//d/e", "f://example.org/base/b/c//d/e"},
511f38d4d45SAdrien Destugues 		{"mid:m@example.ord/c@example.org", "m2@example.ord/c2@example.org",
512f38d4d45SAdrien Destugues 			"mid:m@example.ord/m2@example.ord/c2@example.org"},
513f38d4d45SAdrien Destugues 		{"file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/", "mini1.xml",
514f38d4d45SAdrien Destugues 			"file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml"},
515f38d4d45SAdrien Destugues 		{"foo:a/y/z", "../b/c", "foo:a/b/c"},
516f38d4d45SAdrien Destugues 		{"foo:", "b", "foo:b"},
517f38d4d45SAdrien Destugues 		{"foo://a", "b", "foo://a/b"},
518f38d4d45SAdrien Destugues 		{"foo://a?q", "b", "foo://a/b"},
519f38d4d45SAdrien Destugues 		{"foo://a", "b?q", "foo://a/b?q"},
520f38d4d45SAdrien Destugues 		{"foo://a?r", "b?q", "foo://a/b?q"},
521f38d4d45SAdrien Destugues 	};
522f38d4d45SAdrien Destugues 
523f38d4d45SAdrien Destugues 	BString message(" Base: ");
524f38d4d45SAdrien Destugues 	for (unsigned int index = 0; index < sizeof(tests) / sizeof(RelativeUrl);
525f38d4d45SAdrien Destugues 		index++)
526f38d4d45SAdrien Destugues 	{
527f38d4d45SAdrien Destugues 		NextSubTest();
528f38d4d45SAdrien Destugues 
529f38d4d45SAdrien Destugues 		BUrl baseUrl(tests[index].base);
530f38d4d45SAdrien Destugues 
531f38d4d45SAdrien Destugues 		message.Truncate(7, true);
532f38d4d45SAdrien Destugues 		message << tests[index].base;
533f38d4d45SAdrien Destugues 		message << " Relative: ";
534f38d4d45SAdrien Destugues 		message << tests[index].relative;
535f38d4d45SAdrien Destugues 
536f38d4d45SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL_MESSAGE(message.String(),
537f38d4d45SAdrien Destugues 			BString(tests[index].absolute),
538f38d4d45SAdrien Destugues 			BUrl(baseUrl, tests[index].relative).UrlString());
539f38d4d45SAdrien Destugues 	}
540f38d4d45SAdrien Destugues }
541f38d4d45SAdrien Destugues 
542f38d4d45SAdrien Destugues 
543f38d4d45SAdrien Destugues void
544f38d4d45SAdrien Destugues UrlTest::IDNTest()
545f38d4d45SAdrien Destugues {
546f38d4d45SAdrien Destugues 	// http://www.w3.org/2004/04/uri-rel-test.html
5476da9451eSAdrien Destugues 	// TODO We need to decide wether to store them as UTF-8 or IDNA/punycode.
5486da9451eSAdrien Destugues 
5496da9451eSAdrien Destugues 	struct Test {
5506da9451eSAdrien Destugues 		const char* escaped;
5516da9451eSAdrien Destugues 		const char* decoded;
5526da9451eSAdrien Destugues 	};
5536da9451eSAdrien Destugues 
5546da9451eSAdrien Destugues 	Test tests[] = {
5556da9451eSAdrien Destugues 		{ "http://www.w%33.org", "http://www.w3.org" },
5566da9451eSAdrien Destugues 		{ "http://r%C3%A4ksm%C3%B6rg%C3%A5s.josefsson.org",
5576da9451eSAdrien Destugues 			"http://xn--rksmrgs-5wao1o.josefsson.org" },
5586da9451eSAdrien Destugues 		{ "http://%E7%B4%8D%E8%B1%86.w3.mag.keio.ac.jp",
5596da9451eSAdrien Destugues 			"http://xn--99zt52a.w3.mag.keio.ac.jp" },
5606da9451eSAdrien Destugues 		{ "http://www.%E3%81%BB%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA"
561f38d4d45SAdrien Destugues 			"%E3%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3"
562f38d4d45SAdrien Destugues 			"%82%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82"
563f38d4d45SAdrien Destugues 			"%81%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0"
564f38d4d45SAdrien Destugues 			"%E3%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3"
5656da9451eSAdrien Destugues 			"%81%9F%E3%82%8A%E3%81%AA%E3%81%84.w3.mag.keio.ac.jp/",
5666da9451eSAdrien Destugues 			"http://www.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3fg11amb5gzdb4wi9b"
5676da9451eSAdrien Destugues 			"ya3kc6lra.w3.mag.keio.ac.jp/" },
5686da9451eSAdrien Destugues 
5696da9451eSAdrien Destugues 		{ "http://%E3%81%BB%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA%E3"
570f38d4d45SAdrien Destugues 			"%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3%82"
571f38d4d45SAdrien Destugues 			"%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82%81"
572f38d4d45SAdrien Destugues 			"%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0%E3"
573f38d4d45SAdrien Destugues 			"%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81"
574f38d4d45SAdrien Destugues 			"%9F%E3%82%8A%E3%81%AA%E3%81%84.%E3%81%BB%E3%82%93%E3%81%A8%E3%81"
575f38d4d45SAdrien Destugues 			"%86%E3%81%AB%E3%81%AA%E3%81%8C%E3%81%84%E3%82%8F%E3%81%91%E3%81%AE"
576f38d4d45SAdrien Destugues 			"%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E3%81%A9%E3%82%81%E3"
577f38d4d45SAdrien Destugues 			"%81%84%E3%82%93%E3%82%81%E3%81%84%E3%81%AE%E3%82%89%E3%81%B9%E3%82"
578f38d4d45SAdrien Destugues 			"%8B%E3%81%BE%E3%81%A0%E3%81%AA%E3%81%8C%E3%81%8F%E3%81%97%E3%81%AA"
579f38d4d45SAdrien Destugues 			"%E3%81%84%E3%81%A8%E3%81%9F%E3%82%8A%E3%81%AA%E3%81%84.%E3%81%BB"
580f38d4d45SAdrien Destugues 			"%E3%82%93%E3%81%A8%E3%81%86%E3%81%AB%E3%81%AA%E3%81%8C%E3%81%84%E3"
581f38d4d45SAdrien Destugues 			"%82%8F%E3%81%91%E3%81%AE%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81"
582f38d4d45SAdrien Destugues 			"%84%E3%81%A9%E3%82%81%E3%81%84%E3%82%93%E3%82%81%E3%81%84%E3%81%AE"
583f38d4d45SAdrien Destugues 			"%E3%82%89%E3%81%B9%E3%82%8B%E3%81%BE%E3%81%A0%E3%81%AA%E3%81%8C%E3"
584f38d4d45SAdrien Destugues 			"%81%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81%9F%E3%82%8A%E3%81"
5856da9451eSAdrien Destugues 			"%AA%E3%81%84.w3.mag.keio.ac.jp/",
5866da9451eSAdrien Destugues 			"http://xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3fg11amb5gzdb4wi9bya3k"
5876da9451eSAdrien Destugues 			"c6lra.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3fg11amb5gzdb4wi9bya3kc6"
5886da9451eSAdrien Destugues 			"lra.xn--n8jaaaaai5bhf7as8fsfk3jnknefdde3fg11amb5gzdb4wi9bya3kc6lr"
5896da9451eSAdrien Destugues 			"a.w3.mag.keio.ac.jp/" },
5906da9451eSAdrien Destugues 		{ NULL, NULL }
5916da9451eSAdrien Destugues 	};
5926da9451eSAdrien Destugues 
5936da9451eSAdrien Destugues 	for (int i = 0; tests[i].escaped != NULL; i++)
5946da9451eSAdrien Destugues 	{
5956da9451eSAdrien Destugues 		NextSubTest();
5969bf4e994SAdrien Destugues 
5976da9451eSAdrien Destugues 		BUrl url(tests[i].escaped);
5986da9451eSAdrien Destugues 		url.UrlDecode();
5999bf4e994SAdrien Destugues 
6009bf4e994SAdrien Destugues 		BUrl idn(tests[i].decoded);
6019bf4e994SAdrien Destugues 		status_t success = idn.IDNAToUnicode();
6029bf4e994SAdrien Destugues 
6039bf4e994SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(B_OK, success);
6049bf4e994SAdrien Destugues 		CPPUNIT_ASSERT_EQUAL(url.UrlString(), idn.UrlString());
6056da9451eSAdrien Destugues 	}
606f38d4d45SAdrien Destugues }
607f38d4d45SAdrien Destugues 
608f38d4d45SAdrien Destugues 
609f38d4d45SAdrien Destugues /* static */ void
610f38d4d45SAdrien Destugues UrlTest::AddTests(BTestSuite& parent)
611f38d4d45SAdrien Destugues {
612f38d4d45SAdrien Destugues 	CppUnit::TestSuite& suite = *new CppUnit::TestSuite("UrlTest");
613f38d4d45SAdrien Destugues 
614f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::ParseTest",
615f38d4d45SAdrien Destugues 		&UrlTest::ParseTest));
616f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::TestIsValid",
617f38d4d45SAdrien Destugues 		&UrlTest::TestIsValid));
618f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>(
619f38d4d45SAdrien Destugues 		"UrlTest::TestGettersSetters", &UrlTest::TestGettersSetters));
620f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::TestNullity",
621f38d4d45SAdrien Destugues 		&UrlTest::TestNullity));
622f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::TestCopy",
623f38d4d45SAdrien Destugues 		&UrlTest::TestCopy));
624f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>(
625f38d4d45SAdrien Destugues 		"UrlTest::ExplodeImplodeTest", &UrlTest::ExplodeImplodeTest));
626f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::PathOnly",
627f38d4d45SAdrien Destugues 		&UrlTest::PathOnly));
628f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::RelativeUriTest",
629f38d4d45SAdrien Destugues 		&UrlTest::RelativeUriTest));
630f38d4d45SAdrien Destugues 	suite.addTest(new CppUnit::TestCaller<UrlTest>("UrlTest::IDNTest",
631f38d4d45SAdrien Destugues 		&UrlTest::IDNTest));
632f38d4d45SAdrien Destugues 
633f38d4d45SAdrien Destugues 	parent.addTest("UrlTest", &suite);
634f38d4d45SAdrien Destugues }
635