hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

+test.ha (4258B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use fmt;
      5 use net::ip;
      6 
      7 @test fn roundtrip() void = {
      8 	test_uri_roundtrip(
      9 		"file:///my/path/to/file",
     10 		uri {
     11 			scheme = "file",
     12 			host = "",
     13 			path = "/my/path/to/file",
     14 			...
     15 		},
     16 	)!;
     17 	test_uri_roundtrip(
     18 		"http://harelang.org/",
     19 		uri {
     20 			scheme = "http",
     21 			host = "harelang.org",
     22 			path = "/",
     23 			...
     24 		},
     25 	)!;
     26 	test_uri_roundtrip(
     27 		"irc+insecure://chat.sr.ht:6667",
     28 		uri {
     29 			scheme = "irc+insecure",
     30 			host = "chat.sr.ht",
     31 			port = 6667,
     32 			...
     33 		},
     34 	)!;
     35 	test_uri_roundtrip(
     36 		"ldap://13.37.73.31:1234/",
     37 		uri {
     38 			scheme = "ldap",
     39 			host = [13, 37, 73, 31]: ip::addr4,
     40 			port = 1234,
     41 			path = "/",
     42 			...
     43 		},
     44 	)!;
     45 	test_uri_roundtrip(
     46 		"http://[::1]/test",
     47 		uri {
     48 			scheme = "http",
     49 			host = ip::parse("::1")!,
     50 			path = "/test",
     51 			...
     52 		},
     53 	)!;
     54 
     55 	// Some non-URL variants like mailto: or URN
     56 	test_uri_roundtrip(
     57 		"urn:example:animal:ferret:nose",
     58 		uri {
     59 			scheme = "urn",
     60 			host = "",
     61 			path = "example:animal:ferret:nose",
     62 			...
     63 		},
     64 	)!;
     65 	test_uri_roundtrip(
     66 		"mailto:~sircmpwn/hare-dev@lists.sr.ht",
     67 		uri {
     68 			scheme = "mailto",
     69 			host = "",
     70 			path = "~sircmpwn/hare-dev@lists.sr.ht",
     71 			...
     72 		},
     73 	)!;
     74 	test_uri_roundtrip(
     75 		"http:/foo/bar",
     76 		uri {
     77 			scheme = "http",
     78 			host = "",
     79 			path = "/foo/bar",
     80 			...
     81 		},
     82 	)!;
     83 	test_uri_roundtrip(
     84 		"http:/",
     85 		uri {
     86 			scheme = "http",
     87 			host = "",
     88 			path = "/",
     89 			...
     90 		},
     91 	)!;
     92 	test_uri_roundtrip(
     93 		"https://sr.ht/projects?search=%23risc-v&sort=longest-active#foo",
     94 		uri {
     95 			scheme = "https",
     96 			host = "sr.ht",
     97 			path = "/projects",
     98 			query = "search=%23risc-v&sort=longest-active",
     99 			fragment = "foo",
    100 			...
    101 		},
    102 	)!;
    103 	test_uri_roundtrip(
    104 		"https://en.wiktionary.org/wiki/%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86#Japanese",
    105 		uri {
    106 			scheme = "https",
    107 			host = "en.wiktionary.org",
    108 			path = "/wiki/おはよう",
    109 			fragment = "Japanese",
    110 			...
    111 		}
    112 	)!;
    113 };
    114 
    115 @test fn invalid() void = {
    116 	// Scheme
    117 	assert(parse(":") is invalid);
    118 	assert(parse("hello*:") is invalid);
    119 	assert(parse("hello") is invalid);
    120 
    121 	// Unexpected character
    122 	assert(parse("https://^harelang.org") is invalid);
    123 
    124 	// Trailing stuff after port
    125 	assert(parse("https://harelang.org:1foo2") is invalid);
    126 
    127 	// Something other than IPv6 address inside [ ... ]
    128 	assert(parse("https://[1.2.3.4]") is invalid);
    129 	assert(parse("https://[example]") is invalid);
    130 
    131 	// '@' in userinfo
    132 	assert(parse("https://a@b@example") is invalid);
    133 	assert(parse("https://@@example") is invalid);
    134 };
    135 
    136 @test fn percent_encoding() void = {
    137 	test_uri(
    138 		"https://git%2esr.ht/~sircmpw%6e/hare#Build%20status",
    139 		uri {
    140 			scheme = "https",
    141 			host = "git.sr.ht",
    142 			path = "/~sircmpwn/hare",
    143 			fragment = "Build status",
    144 			...
    145 		},
    146 		"https://git.sr.ht/~sircmpwn/hare#Build%20status",
    147 	)!;
    148 
    149 	// IPv6
    150 	test_uri(
    151 		"ldap://[2001:db8::7]/c=GB?objectClass?one",
    152 		uri {
    153 			scheme = "ldap",
    154 			host = ip::parse("2001:db8::7")!,
    155 			path = "/c=GB",
    156 			query = "objectClass?one",
    157 			...
    158 		},
    159 		"ldap://[2001:db8::7]/c=GB?objectClass?one",
    160 	)!;
    161 
    162 	// https://bugs.chromium.org/p/chromium/issues/detail?id=841105
    163 	test_uri(
    164 		"https://web-safety.net/..;@www.google.com:%3443",
    165 		uri {
    166 			scheme = "https",
    167 			host = "web-safety.net",
    168 			path = "/..;@www.google.com:443",
    169 			...
    170 		},
    171 		"https://web-safety.net/..;@www.google.com:443",
    172 	)!;
    173 };
    174 
    175 fn test_uri_roundtrip(in: str, expected: uri) (void | invalid) = {
    176 	test_uri(in, expected, in)?;
    177 };
    178 
    179 fn test_uri(in: str, expected_uri: uri, expected_str: str) (void | invalid) = {
    180 	const u = parse(in)?;
    181 	defer finish(&u);
    182 
    183 	assert_str(u.scheme, expected_uri.scheme);
    184 	match (u.host) {
    185 	case let s: str =>
    186 		assert_str(s, expected_uri.host as str);
    187 	case let i: ip::addr =>
    188 		assert(ip::equal(i, expected_uri.host as ip::addr));
    189 	};
    190 	assert(u.port == expected_uri.port);
    191 	assert_str(u.userinfo, expected_uri.userinfo);
    192 	assert_str(u.path, expected_uri.path);
    193 	assert_str(u.query, expected_uri.query);
    194 	assert_str(u.fragment, expected_uri.fragment);
    195 
    196 	const s = string(&u);
    197 	defer free(s);
    198 
    199 	assert_str(s, expected_str);
    200 };
    201 
    202 fn assert_str(got: str, expected: str) void = {
    203 	if (got != expected) {
    204 		fmt::errorfln("=== wanted\n{}", expected)!;
    205 		fmt::errorfln("=== got\n{}", got)!;
    206 		abort();
    207 	};
    208 };