
UriTest.pudu
Pudu67 lines6.2 KB
1/** @Test.Domain.Uri.Suite — splitting, resolving, and reducing addresses */2module PuduLangHttpClient.Domain.UriTest34import Std.Char as Char5import Std.Io as Io6import Std.Option as Option7import Std.Test as Test8import Std.Text as Text9import PuduLangHttpClient.Domain.Uri as Uri101112const BASE: Str = "http://a/b/c/d;p?q"131415const EXAMPLES: Array[(Str, Str)] = [16 ("g:h", "g:h"), ("g", "http://a/b/c/g"), ("./g", "http://a/b/c/g"), ("g/", "http://a/b/c/g/"),17 ("/g", "http://a/g"), ("//g", "http://g"), ("?y", "http://a/b/c/d;p?y"), ("g?y", "http://a/b/c/g?y"),18 ("#s", "http://a/b/c/d;p?q#s"), ("g#s", "http://a/b/c/g#s"), ("g?y#s", "http://a/b/c/g?y#s"),19 (";x", "http://a/b/c/;x"), ("g;x", "http://a/b/c/g;x"), ("g;x?y#s", "http://a/b/c/g;x?y#s"),20 ("", "http://a/b/c/d;p?q"), (".", "http://a/b/c/"), ("./", "http://a/b/c/"), ("..", "http://a/b/"),21 ("../", "http://a/b/"), ("../g", "http://a/b/g"), ("../..", "http://a/"), ("../../", "http://a/"),22 ("../../g", "http://a/g"), ("../../../g", "http://a/g"), ("../../../../g", "http://a/g"),23 ("/./g", "http://a/g"), ("/../g", "http://a/g"), ("g.", "http://a/b/c/g."), (".g", "http://a/b/c/.g"),24 ("g..", "http://a/b/c/g.."), ("..g", "http://a/b/c/..g"), ("./../g", "http://a/b/g"),25 ("./g/.", "http://a/b/c/g/"), ("g/./h", "http://a/b/c/g/h"), ("g/../h", "http://a/b/c/h"),26 ("g;x=1/./y", "http://a/b/c/g;x=1/y"), ("g;x=1/../y", "http://a/b/c/y"), ("g?y/./x", "http://a/b/c/g?y/./x"),27 ("g?y/../x", "http://a/b/c/g?y/../x"), ("g#s/./x", "http://a/b/c/g#s/./x"), ("g#s/../x", "http://a/b/c/g#s/../x"),28 ("http:g", "http:g")29]303132fn main() -> Int {33 let resolved = EXAMPLES.filter(|pair: (Str, Str)| Uri.resolve(BASE, pair[0]) != pair[1]).map(|pair: (Str, Str)| pair[0] + " -> " + Uri.resolve(BASE, pair[0]))34 let parts = Uri.split("https://user@example.com:8443/a/b?x=1#top")35 let checks = Test.suite("Domain.Uri", &[36 Test.equals("every reference example resolves as specified", &resolved, &[]),37 Test.equals("an address splits into its five components", &parts, &Uri.Parts{scheme: Some("https"), authority: Some("user@example.com:8443"), path: "/a/b", query: Some("x=1"), fragment: Some("top")}),38 Test.equals("an empty query is kept apart from no query", &(Uri.split("/a?").query, Uri.split("/a").query), &(Some(""), None)),39 Test.equals("joining the components writes the address back", &Uri.join(&parts), &"https://user@example.com:8443/a/b?x=1#top"),40 Test.that("an address with a scheme is absolute", Uri.isAbsolute("http://a/") && Uri.isAbsolute("mailto:x")),41 Test.not("a path or a reference without a scheme is relative", Uri.isAbsolute("/a/b") || Uri.isAbsolute("a:b/c".drop(2)) || Uri.isAbsolute("1a:b")),42 Test.equals("a base address with a trailing slash keeps its last segment", &Uri.resolve("https://api.test/v1/", "users"), &"https://api.test/v1/users"),43 Test.equals("a base address without a trailing slash loses its last segment", &Uri.resolve("https://api.test/v1", "users"), &"https://api.test/users"),44 Test.equals("an authority without a path merges under the root", &Uri.resolve("https://api.test", "users"), &"https://api.test/users"),45 Test.equals("an https endpoint uses port 443 by default", &Uri.endpointOf("HTTPS://Example.COM/x"), &Some(Uri.Endpoint{scheme: "https", host: "example.com", port: 443, secure: true})),46 Test.equals("an http endpoint reads its port and drops user information", &Uri.endpointOf("http://u:p@localhost:8080"), &Some(Uri.Endpoint{scheme: "http", host: "localhost", port: 8080, secure: false})),47 Test.equals("an IPv6 literal loses its brackets", &Uri.endpointOf("http://[::1]:9000/"), &Some(Uri.Endpoint{scheme: "http", host: "::1", port: 9000, secure: false})),48 Test.equals("other schemes, relative addresses, and bad ports have no endpoint", &[Uri.endpointOf("ftp://a/"), Uri.endpointOf("/a"), Uri.endpointOf("http://a:0/"), Uri.endpointOf("http://a:70000/"), Uri.endpointOf("http://a:x/"), Uri.endpointOf("http:///a")], &[None, None, None, None, None, None]),49 Test.equals("the authority omits the scheme's own port", &(Uri.authority(&Uri.Endpoint{scheme: "http", host: "a", port: 80, secure: false}), Uri.authority(&Uri.Endpoint{scheme: "https", host: "a", port: 80, secure: true}), Uri.authority(&Uri.Endpoint{scheme: "http", host: "::1", port: 81, secure: false})), &("a", "a:80", "[::1]:81")),50 Test.equals("an origin is the scheme and the authority", &Uri.origin(&Uri.Endpoint{scheme: "https", host: "a", port: 444, secure: true}), &"https://a:444"),51 Test.equals("the target is the path and query, never the fragment", &(Uri.target("http://a"), Uri.target("http://a/b?c=d#e"), Uri.target("http://a?x")), &("/", "/b?c=d", "/?x")),52 Test.equals("the fragment is dropped before sending", &Uri.withoutFragment("http://a/b#c"), &"http://a/b"),53 Test.equals("characters a request line cannot carry are escaped as UTF-8", &Uri.escape("/a b/ñ\r\n?q=é"), &"/a%20b/%C3%B1%0D%0A?q=%C3%A9"),54 Test.equals("a lone dot or double dot path is removed entirely", &(Uri.removeDotSegments("."), Uri.removeDotSegments("..")), &("", "")),55 Test.equals("the delete character is escaped", &Uri.escape(Text.singleton(Option.unwrapOr(Char.fromCode(127), 'x'))), &"%7F"),56 Test.equals("a port of 1 or 65535 is a port", &(Option.map(Uri.endpointOf("http://a:1/"), |e: Uri.Endpoint| e.port), Option.map(Uri.endpointOf("http://a:65535/"), |e: Uri.Endpoint| e.port)), &(Some(1), Some(65535))),57 Test.that("a scheme may hold letters, digits, plus, minus, and dot", Uri.isAbsolute("svn+ssh://h") && Uri.isAbsolute("x-y:z") && Uri.isAbsolute("x.y:z") && Uri.isAbsolute("h2:z")),58 Test.not("a scheme may hold nothing else, nor be empty or missing", Uri.isAbsolute("a_b:z") || Uri.isAbsolute("a b:z") || Uri.isAbsolute(":x") || Uri.isAbsolute("relative") || Uri.isAbsolute("")),59 Test.equals("dot segments are removed", &(Uri.removeDotSegments("/a/b/c/./../../g"), Uri.removeDotSegments("mid/content=5/../6")), &("/a/g", "mid/6"))60 ])61 let ran = Test.run(&checks)62 for failure in Test.failuresOf(&ran) {63 let _reported = Io.writeErrorLine(failure)64 }65 Test.report(&ran)66}67