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