with comments, less is more
[uri.git] / uri-test.cpp
blob7a5b68524c4d86f492b0cdcc0f180bc63ce9bfdb
1 #include "uri.hpp"
3 #include <glog/logging.h>
5 int test_good()
7 struct test_case {
8 char const* uri;
9 uri::components parts;
12 // clang-format off
13 test_case tests[] = {
14 {"foo://dude@example.com:8042/over/there?name=ferret#nose",
15 {"foo", "dude@example.com:8042", "dude", "example.com", "8042", "/over/there", "name=ferret", "nose", }, },
17 {"foo://example.com:8042/over/there?name=ferret#nose",
18 {"foo", "example.com:8042", {}, "example.com", "8042", "/over/there", "name=ferret", "nose", }, },
20 {"ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm",
21 {"ftp", "cnn.example.com&story=breaking_news@10.0.0.1", "cnn.example.com&story=breaking_news", "10.0.0.1", {}, "/top_story.htm", {}, {}, }, },
23 {"ftp://foo.bar/baz",
24 {"ftp", "foo.bar", {}, "foo.bar", {}, "/baz", {}, {}, }, },
26 {"ftp://ftp.is.co.za/rfc/rfc1808.txt",
27 {"ftp", "ftp.is.co.za", {}, "ftp.is.co.za", {}, "/rfc/rfc1808.txt", {}, {}, }, },
29 {"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
30 {"http", "-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "-.~_!$&'()*+,;=:%40:80%2f::::::", "example.com", {}, "", {}, {}, }, },
32 {"http://1337.net",
33 {"http", "1337.net", {}, "1337.net", {}, "", {}, {}, }, },
35 {"http://142.42.1.1/",
36 {"http", "142.42.1.1", {}, "142.42.1.1", {}, "/", {}, {}, }, },
38 {"http://142.42.1.1:8080/",
39 {"http", "142.42.1.1:8080", {}, "142.42.1.1", "8080", "/", {}, {}, }, },
41 {"http://223.255.255.254",
42 {"http", "223.255.255.254", {}, "223.255.255.254", {}, "", {}, {}, }, },
44 {"http://a.b-c.de",
45 {"http", "a.b-c.de", {}, "a.b-c.de", {}, "", {}, {}, }, },
47 {"http://code.google.com/events/#&product=browser",
48 {"http", "code.google.com", {}, "code.google.com", {}, "/events/", {}, "&product=browser", }, },
50 {"http://example.com",
51 {"http", "example.com", {}, "example.com", {}, "", {}, {}, }, },
53 {"http://example.com/",
54 {"http", "example.com", {}, "example.com", {}, "/", {}, {}, }, },
56 {"http://example.com:",
57 {"http", "example.com:", {}, "example.com", "", "", {}, {}, }, },
59 {"http://example.com:/",
60 {"http", "example.com:", {}, "example.com", "", "/", {}, {}, }, },
62 {"http://example.com:80",
63 {"http", "example.com:80", {}, "example.com", "80", "", {}, {}, }, },
65 {"http://example.com:80/",
66 {"http", "example.com:80", {}, "example.com", "80", "/", {}, {}, }, },
68 {"http://foo.bar/?q=Test%20URL-encoded%20stuff",
69 {"http", "foo.bar", {}, "foo.bar", {}, "/", "q=Test%20URL-encoded%20stuff", {}, }, },
71 {"http://foo.com/(something)?after=parens",
72 {"http", "foo.com", {}, "foo.com", {}, "/(something)", "after=parens", {}, }, },
74 {"http://foo.com/blah_(wikipedia)#cite-1",
75 {"http", "foo.com", {}, "foo.com", {}, "/blah_(wikipedia)", {}, "cite-1", }, },
77 {"http://foo.com/blah_(wikipedia)_blah#cite-1",
78 {"http", "foo.com", {}, "foo.com", {}, "/blah_(wikipedia)_blah", {}, "cite-1", }, },
80 {"http://foo.com/blah_blah",
81 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah", {}, {}, }, },
83 {"http://foo.com/blah_blah/",
84 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah/", {}, {}, }, },
86 {"http://foo.com/blah_blah_(wikipedia)",
87 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah_(wikipedia)", {}, {}, }, },
89 {"http://foo.com/blah_blah_(wikipedia)_(again)",
90 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah_(wikipedia)_(again)", {}, {}, }, },
92 {"http://foo.com/unicode_(✪)_in_parens",
93 {"http", "foo.com", {}, "foo.com", {}, "/unicode_(✪)_in_parens", {}, {}, }, },
95 {"http://j.mp",
96 {"http", "j.mp", {}, "j.mp", {}, "", {}, {}, }, },
98 {"http://userid:password@example.com",
99 {"http", "userid:password@example.com", "userid:password", "example.com", {}, "", {}, {}, }, },
101 {"http://userid:password@example.com/",
102 {"http", "userid:password@example.com", "userid:password", "example.com", {}, "/", {}, {}, }, },
104 {"http://userid:password@example.com:8080",
105 {"http", "userid:password@example.com:8080", "userid:password", "example.com", "8080", "", {}, {}, }, },
107 {"http://userid:password@example.com:8080/",
108 {"http", "userid:password@example.com:8080", "userid:password", "example.com", "8080", "/", {}, {}, }, },
110 {"http://userid@example.com",
111 {"http", "userid@example.com", "userid", "example.com", {}, "", {}, {}, }, },
113 {"http://userid@example.com/",
114 {"http", "userid@example.com", "userid", "example.com", {}, "/", {}, {}, }, },
116 {"http://userid@example.com:8080",
117 {"http", "userid@example.com:8080", "userid", "example.com", "8080", "", {}, {}, }, },
119 {"http://userid@example.com:8080/",
120 {"http", "userid@example.com:8080", "userid", "example.com", "8080", "/", {}, {}, }, },
122 {"http://www.example.com/wpstyle/?p=364",
123 {"http", "www.example.com", {}, "www.example.com", {}, "/wpstyle/", "p=364", {}, }, },
125 {"http://www.ics.uci.edu/pub/ietf/uri/#Related",
126 {"http", "www.ics.uci.edu", {}, "www.ics.uci.edu", {}, "/pub/ietf/uri/", {}, "Related", }, },
128 {"http://www.ietf.org/rfc/rfc2396.txt",
129 {"http", "www.ietf.org", {}, "www.ietf.org", {}, "/rfc/rfc2396.txt", {}, {}, }, },
131 {"http://مثال.إختبار",
132 {"http", "مثال.إختبار", {}, "مثال.إختبار", {}, "", {}, {}, }, },
134 {"http://उदाहरण.परीक्षा",
135 {"http", "उदाहरण.परीक्षा", {}, "उदाहरण.परीक्षा", {}, "", {}, {}, }, },
137 {"http://⌘.ws",
138 {"http", "⌘.ws", {}, "⌘.ws", {}, "", {}, {}, }, },
140 {"http://⌘.ws/",
141 {"http", "⌘.ws", {}, "⌘.ws", {}, "/", {}, {}, }, },
143 {"http://☺.damowmow.com/",
144 {"http", "☺.damowmow.com", {}, "☺.damowmow.com", {}, "/", {}, {}, }, },
146 {"http://✪df.ws/123",
147 {"http", "✪df.ws", {}, "✪df.ws", {}, "/123", {}, {}, }, },
149 {"http://➡.ws/䨹",
150 {"http", "➡.ws", {}, "➡.ws", {}, "/䨹", {}, {}, }, },
152 {"http://例子.测试",
153 {"http", "例子.测试", {}, "例子.测试", {}, "", {}, {}, }, },
155 {"https://tools.ietf.org/html/rfc3986#appendix-B",
156 {"https", "tools.ietf.org", {}, "tools.ietf.org", {}, "/html/rfc3986", {}, "appendix-B", }, },
158 {"https://www.example.com/foo/?bar=baz&inga=42&quux",
159 {"https", "www.example.com", {}, "www.example.com", {}, "/foo/", "bar=baz&inga=42&quux", {}, }, },
161 {"https://xn%2D%2Dui8h%2Edigilicious%2Ecom/",
162 {"https", "xn%2D%2Dui8h%2Edigilicious%2Ecom", {}, "xn%2D%2Dui8h%2Edigilicious%2Ecom", {}, "/", {}, {}, }, },
164 {"https://xn--ui8h%2Edigilicious%2Ecom/",
165 {"https", "xn--ui8h%2Edigilicious%2Ecom", {}, "xn--ui8h%2Edigilicious%2Ecom", {}, "/", {}, {}, }, },
167 {"https://xn--ui8h.digilicious.com/",
168 {"https", "xn--ui8h.digilicious.com", {}, "xn--ui8h.digilicious.com", {}, "/", {}, {}, }, },
170 {"https://🍔.digilicious.com/",
171 {"https", "🍔.digilicious.com", {}, "🍔.digilicious.com", {}, "/", {}, {}, }, },
173 {"ldap://[2001:db8::7]/c=GB?objectClass?one",
174 {"ldap", "[2001:db8::7]", {}, "[2001:db8::7]", {}, "/c=GB", "objectClass?one", {}, }, },
176 {"mailto:John.Doe@example.com",
177 {"mailto", {}, {}, {}, {}, "John.Doe@example.com", {}, {}, }, },
179 {"news:comp.infosystems.www.servers.unix",
180 {"news", {}, {}, {}, {}, "comp.infosystems.www.servers.unix", {}, {}, }, },
182 {"tel:+1-816-555-1212",
183 {"tel", {}, {}, {}, {}, "+1-816-555-1212", {}, {}, }, },
185 {"telnet://192.0.2.16:80/",
186 {"telnet", "192.0.2.16:80", {}, "192.0.2.16", "80", "/", {}, {}, }, },
188 {"urn:example:animal:ferret:nose",
189 {"urn", {}, {}, {}, {}, "example:animal:ferret:nose", {}, {}, }, },
191 {"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
192 {"urn", {}, {}, {}, {}, "oasis:names:specification:docbook:dtd:xml:4.1.2", {}, {}, }, },
194 // clang-format on
196 auto failures = 0;
198 for (auto&& test : tests) {
199 uri::generic u{test.uri};
200 if (test.parts != u.parts()) {
201 std::cerr << test.uri << " failed to check\n";
203 std::cout << "URL:\n";
204 if (u.scheme())
205 std::cout << "scheme() == " << *u.scheme() << '\n';
206 if (u.authority())
207 std::cout << "authority() == " << *u.authority() << '\n';
208 if (u.userinfo())
209 std::cout << "userinfo() == " << *u.userinfo() << '\n';
210 if (u.host())
211 std::cout << "host() == " << *u.host() << '\n';
212 if (u.port())
213 std::cout << "port() == " << *u.port() << '\n';
214 if (u.path())
215 std::cout << "path() == " << *u.path() << '\n';
216 if (u.query())
217 std::cout << "query() == " << *u.query() << '\n';
218 if (u.fragment())
219 std::cout << "fragment() == " << *u.fragment() << '\n';
221 std::cout << "\ntest:\n";
223 if (test.parts.scheme)
224 std::cout << "scheme == " << *test.parts.scheme << '\n';
225 if (test.parts.authority)
226 std::cout << "authority == " << *test.parts.authority << '\n';
227 if (test.parts.userinfo)
228 std::cout << "userinfo == " << *test.parts.userinfo << '\n';
229 if (test.parts.host)
230 std::cout << "host == " << *test.parts.host << '\n';
231 if (test.parts.port)
232 std::cout << "port == " << *test.parts.port << '\n';
233 if (test.parts.path)
234 std::cout << "path == " << *test.parts.path << '\n';
235 if (test.parts.query)
236 std::cout << "query == " << *test.parts.query << '\n';
237 if (test.parts.fragment)
238 std::cout << "fragment == " << *test.parts.fragment << '\n';
240 std::cout << "\n";
242 ++failures;
246 return failures;
249 int test_bad()
251 // Verify a bunch of bad URIs all throw exceptions.
252 auto failures = 0;
254 char const* bad_uris[]{
255 "http://",
256 "http://.",
257 "http://..",
258 "http://../",
259 "http://?",
260 "http://?\?",
261 "http://?\?/",
262 "http://#",
263 "http://##",
264 "http://##/",
265 "http://foo.bar?q=Spaces should be encoded",
266 "//",
267 "//a",
268 "///a",
269 "///",
270 "http:///a",
271 "foo.com",
272 "http:// shouldfail.com",
273 ":// should fail",
274 "http://foo.bar/foo(bar)baz quux",
275 "http://-error-.invalid/",
276 "http://-a.b.co",
277 "http://a.b-.co",
278 "http://1.1.1.1.1",
279 "http://.www.foo.bar/",
280 "http://.www.foo.bar./",
283 // I have to confess, I don't know what's wrong with these:
285 // "ftps://foo.bar/",
286 // "http://a.b--c.de/",
287 // "rdar://1234",
288 // "h://test",
289 // "http://0.0.0.0",
290 // "http://10.1.1.0",
291 // "http://10.1.1.255",
292 // "http://224.1.1.1",
293 // "http://123.123.123",
294 // "http://3628126748",
295 // "http://10.1.1.1",
296 // "http://10.1.1.254",
297 // "http://www.foo.bar./",
299 for (auto uri : bad_uris) {
300 try {
301 uri::generic u{uri};
302 LOG(ERROR) << "should not parse \"" << uri << "\" as \"" << u << "\"\n";
303 ++failures;
305 catch (uri::syntax_error const& e) {
306 // all good
308 catch (std::exception const& e) {
309 LOG(FATAL) << "unexpected exception " << e.what() << '\n';
313 return failures;
316 int test_resolution()
318 struct test_case {
319 char const* ref;
320 char const* resolved;
323 // clang-format off
324 test_case tests[] = {
326 // 5.4.1. Normal Examples
328 {"g:h", "g:h"},
329 {"g", "http://a/b/c/g"},
330 {"./g", "http://a/b/c/g"},
331 {"g/", "http://a/b/c/g/"},
332 {"/g", "http://a/g"},
333 {"//g", "http://g"},
334 {"?y", "http://a/b/c/d;p?y"},
335 {"g?y", "http://a/b/c/g?y"},
336 {"#s", "http://a/b/c/d;p?q#s"},
337 {"g#s", "http://a/b/c/g#s"},
338 {"g?y#s", "http://a/b/c/g?y#s"},
339 {";x", "http://a/b/c/;x"},
340 {"g;x", "http://a/b/c/g;x"},
341 {"g;x?y#s", "http://a/b/c/g;x?y#s"},
342 {"", "http://a/b/c/d;p?q"},
343 {".", "http://a/b/c/"},
344 {"./", "http://a/b/c/"},
345 {"..", "http://a/b/"},
346 {"../", "http://a/b/"},
347 {"../g", "http://a/b/g"},
348 {"../..", "http://a/"},
349 {"../../", "http://a/"},
350 {"../../g", "http://a/g"},
352 // 5.4.2. Abnormal Examples
354 {"../../../g", "http://a/g"},
355 {"../../../../g", "http://a/g"},
357 {"/./g", "http://a/g"},
358 {"/../g", "http://a/g"},
359 {"g.", "http://a/b/c/g."},
360 {".g", "http://a/b/c/.g"},
361 {"g..", "http://a/b/c/g.."},
362 {"..g", "http://a/b/c/..g"},
364 {"g?y/./x", "http://a/b/c/g?y/./x"},
365 {"g?y/../x", "http://a/b/c/g?y/../x"},
366 {"g#s/./x", "http://a/b/c/g#s/./x"},
367 {"g#s/../x", "http://a/b/c/g#s/../x"},
369 {"http:g", "http:g"}, // for strict parsers
371 // clang-format on
373 // 5.4. Reference Resolution Examples
375 uri::absolute base("http://a/b/c/d;p?q");
377 auto failures = 0;
379 for (auto&& test : tests) {
380 uri::reference ref(test.ref);
381 auto resolved = uri::resolve_ref(base, ref);
382 auto resolved_str = uri::to_string(resolved);
383 if (resolved_str != test.resolved) {
384 LOG(ERROR) << "##### Failure #####";
385 LOG(ERROR) << "for input == " << test.ref << '\n';
386 LOG(ERROR) << "ref == " << ref;
387 LOG(ERROR) << "resolved == " << resolved;
388 LOG(ERROR) << "should match == " << test.resolved;
389 ++failures;
393 return failures;
396 int main(int argc, char* argv[])
398 auto failures = 0;
400 failures += test_good();
401 failures += test_bad();
402 failures += test_resolution();
405 // the two explicit tests from RFC 3986:
406 uri::components parts;
407 parts.path = "/a/b/c/./../../g";
408 CHECK_EQ(uri::normalize(parts), "/a/g");
409 parts.path = "mid/content=5/../6";
410 CHECK_EQ(uri::normalize(parts), "mid/6");
413 // Parse command line args as URIs.
415 for (auto i = 1; i < argc; ++i) {
416 uri::reference u{argv[i]};
418 std::cout << "scheme == " << (u.scheme() ? *u.scheme() : "{}") << '\n'
419 << "auth == " << (u.authority() ? *u.authority() : "{}") << '\n'
420 << "user == " << (u.userinfo() ? *u.userinfo() : "{}") << '\n'
421 << "host == " << (u.host() ? *u.host() : "{}") << '\n'
422 << "port == " << (u.port() ? *u.port() : "{}") << '\n'
423 << "path == " << (u.path() ? *u.path() : "{}") << '\n'
424 << "query == " << (u.query() ? *u.query() : "{}") << '\n'
425 << "frag == " << (u.fragment() ? *u.fragment() : "{}") << '\n';
427 std::cout << "string == " << uri::to_string(u) << '\n';
429 std::cout << "norm == " << uri::normalize(u.parts()) << '\n';
432 if (failures)
433 LOG(FATAL) << "one or more tests failed";