hare

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

+test.ha (3942B)


      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 		"https://sr.ht/projects?search=%23risc-v&sort=longest-active#foo",
     76 		uri {
     77 			scheme = "https",
     78 			host = "sr.ht",
     79 			path = "/projects",
     80 			query = "search=%23risc-v&sort=longest-active",
     81 			fragment = "foo",
     82 			...
     83 		},
     84 	)!;
     85 	test_uri_roundtrip(
     86 		"https://en.wiktionary.org/wiki/%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86#Japanese",
     87 		uri {
     88 			scheme = "https",
     89 			host = "en.wiktionary.org",
     90 			path = "/wiki/おはよう",
     91 			fragment = "Japanese",
     92 			...
     93 		}
     94 	)!;
     95 };
     96 
     97 @test fn invalid() void = {
     98 	// Scheme
     99 	assert(parse(":") is invalid);
    100 	assert(parse("hello*:") is invalid);
    101 	assert(parse("hello") is invalid);
    102 
    103 	// Unexpected character
    104 	assert(parse("https://^harelang.org") is invalid);
    105 
    106 	// Something other than IPv6 address inside [ ... ]
    107 	assert(parse("https://[1.2.3.4]") is invalid);
    108 	assert(parse("https://[example]") is invalid);
    109 
    110 	// '@' in userinfo
    111 	assert(parse("https://a@b@example") is invalid);
    112 	assert(parse("https://@@example") is invalid);
    113 };
    114 
    115 @test fn percent_encoding() void = {
    116 	test_uri(
    117 		"https://git%2esr.ht/~sircmpw%6e/hare#Build%20status",
    118 		uri {
    119 			scheme = "https",
    120 			host = "git.sr.ht",
    121 			path = "/~sircmpwn/hare",
    122 			fragment = "Build status",
    123 			...
    124 		},
    125 		"https://git.sr.ht/~sircmpwn/hare#Build%20status",
    126 	)!;
    127 
    128 	// IPv6
    129 	test_uri(
    130 		"ldap://[2001:db8::7]/c=GB?objectClass?one",
    131 		uri {
    132 			scheme = "ldap",
    133 			host = ip::parse("2001:db8::7")!,
    134 			path = "/c=GB",
    135 			query = "objectClass?one",
    136 			...
    137 		},
    138 		"ldap://[2001:db8::7]/c=GB?objectClass?one",
    139 	)!;
    140 
    141 	// https://bugs.chromium.org/p/chromium/issues/detail?id=841105
    142 	test_uri(
    143 		"https://web-safety.net/..;@www.google.com:%3443",
    144 		uri {
    145 			scheme = "https",
    146 			host = "web-safety.net",
    147 			path = "/..;@www.google.com:443",
    148 			...
    149 		},
    150 		"https://web-safety.net/..;@www.google.com:443",
    151 	)!;
    152 };
    153 
    154 fn test_uri_roundtrip(in: str, expected: uri) (void | invalid) = {
    155 	test_uri(in, expected, in)?;
    156 };
    157 
    158 fn test_uri(in: str, expected_uri: uri, expected_str: str) (void | invalid) = {
    159 	const u = parse(in)?;
    160 	defer finish(&u);
    161 
    162 	assert_str(u.scheme, expected_uri.scheme);
    163 	match (u.host) {
    164 	case let s: str =>
    165 		assert_str(s, expected_uri.host as str);
    166 	case let i: ip::addr =>
    167 		assert(ip::equal(i, expected_uri.host as ip::addr));
    168 	};
    169 	assert(u.port == expected_uri.port);
    170 	assert_str(u.userinfo, expected_uri.userinfo);
    171 	assert_str(u.path, expected_uri.path);
    172 	assert_str(u.query, expected_uri.query);
    173 	assert_str(u.fragment, expected_uri.fragment);
    174 
    175 	const s = string(&u);
    176 	defer free(s);
    177 
    178 	assert_str(s, expected_str);
    179 };
    180 
    181 fn assert_str(got: str, expected: str) void = {
    182 	if (got != expected) {
    183 		fmt::errorfln("=== wanted\n{}", expected)!;
    184 		fmt::errorfln("=== got\n{}", got)!;
    185 		abort();
    186 	};
    187 };