+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 };