diff options
-rw-r--r-- | bin/run-tests.js | 6 | ||||
-rw-r--r-- | src/gleam/should.gleam | 5 | ||||
-rw-r--r-- | src/gleam/uri.gleam | 110 | ||||
-rw-r--r-- | test/gleam/uri_test.gleam | 94 |
4 files changed, 145 insertions, 70 deletions
diff --git a/bin/run-tests.js b/bin/run-tests.js index 46e7963..a142944 100644 --- a/bin/run-tests.js +++ b/bin/run-tests.js @@ -11,17 +11,17 @@ async function main() { for await (let entry of await opendir(dir)) { if (!entry.name.endsWith("_test.js")) continue; let path = "../" + dir + entry.name; - process.stdout.write("\ngleam/" + entry.name.slice(0, -3) + ":\n "); + // process.stdout.write("\ngleam/" + entry.name.slice(0, -3) + ":\n "); let module = await import(path); for (let fnName of Object.keys(module)) { if (!fnName.endsWith("_test")) continue; try { module[fnName](); - process.stdout.write("✨"); + process.stdout.write(`\u001b[${32}m.\u001b[${0}m`); passes++; } catch (error) { - process.stdout.write(`❌ ${fnName}: ${error}\n `); + process.stdout.write(`\n❌ ${fnName}: ${error}\n`); failures++; } } diff --git a/src/gleam/should.gleam b/src/gleam/should.gleam index 3566dc2..5a636d0 100644 --- a/src/gleam/should.gleam +++ b/src/gleam/should.gleam @@ -34,11 +34,10 @@ if javascript { True -> Nil _ -> crash(string.concat([ - "\n", + "\n\t", stringify(a), - "\nshould equal \n", + "\n\tshould equal \n\t", stringify(b), - "\n", ])) } } diff --git a/src/gleam/uri.gleam b/src/gleam/uri.gleam index b40b381..882f17e 100644 --- a/src/gleam/uri.gleam +++ b/src/gleam/uri.gleam @@ -7,31 +7,35 @@ //// Query encoding (Form encoding) is defined in the w3c specification. //// https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data +import gleam/option.{None, Option, Some} +import gleam/string +import gleam/int + if erlang { import gleam/list import gleam/result - import gleam/option.{None, Option, Some} - import gleam/string import gleam/dynamic.{Dynamic} import gleam/map.{Map} import gleam/function import gleam/pair +} - /// Type representing holding the parsed components of an URI. - /// All components of a URI are optional, except the path. - /// - pub type Uri { - Uri( - scheme: Option(String), - userinfo: Option(String), - host: Option(String), - port: Option(Int), - path: String, - query: Option(String), - fragment: Option(String), - ) - } +/// Type representing holding the parsed components of an URI. +/// All components of a URI are optional, except the path. +/// +pub type Uri { + Uri( + scheme: Option(String), + userinfo: Option(String), + host: Option(String), + port: Option(Int), + path: String, + query: Option(String), + fragment: Option(String), + ) +} +if erlang { pub external fn erl_parse(String) -> Dynamic = "uri_string" "parse" @@ -220,47 +224,45 @@ if erlang { external fn erl_to_string(Map(UriKey, Dynamic)) -> Dynamic = "uri_string" "recompose" +} - /// Encodes a `Uri` value as a URI string. - /// - /// The opposite operation is `uri.parse`. - /// - /// ## Examples - /// - /// ``` - /// > let uri = Uri(Some("http"), None, Some("example.com"), ...) - /// > to_string(uri) - /// - /// "https://example.com" - /// ``` - /// - pub fn to_string(uri: Uri) -> String { - let field = fn(key: UriKey, value: Option(anything)) -> Result( - #(UriKey, Dynamic), - Nil, - ) { - case value { - Some(v) -> Ok(#(key, dynamic.from(v))) - None -> Error(Nil) - } - } - - [ - field(Scheme, uri.scheme), - field(Userinfo, uri.userinfo), - field(Host, uri.host), - field(Port, uri.port), - field(Path, option.Some(uri.path)), - field(Query, uri.query), - field(Fragment, uri.fragment), - ] - |> list.filter_map(fn(x) { x }) - |> map.from_list - |> erl_to_string - |> dynamic.string - |> result.unwrap("") +/// Encodes a `Uri` value as a URI string. +/// +/// The opposite operation is `uri.parse`. +/// +/// ## Examples +/// +/// ``` +/// > let uri = Uri(Some("http"), None, Some("example.com"), ...) +/// > to_string(uri) +/// +/// "https://example.com" +/// ``` +/// +pub fn to_string(uri: Uri) -> String { + // TODO: query + // TODO: fragment + let parts = [] + let parts = [uri.path, ..parts] + let parts = case uri.host, string.starts_with(uri.path, "/") { + Some(_), False -> ["/", ..parts] + _, _ -> parts + } + let parts = case uri.host, uri.port { + Some(_), Some(port) -> [":", int.to_string(port), ..parts] + _, _ -> parts } + let parts = case uri.scheme, uri.userinfo, uri.host { + Some(s), Some(u), Some(h) -> [s, ":", u, "@", h, ..parts] + Some(s), None, Some(h) -> [s, "://", h, ..parts] + Some(s), Some(_), None | Some(s), None, None -> [s, ":", ..parts] + None, None, Some(h) -> ["//", h, ..parts] + None, Some(_), None | None, None, None -> parts + } + string.concat(parts) +} +if erlang { /// Fetches the origin of a uri /// /// Return the origin of a uri as defined in diff --git a/test/gleam/uri_test.gleam b/test/gleam/uri_test.gleam index 9c6d2e0..45fe73e 100644 --- a/test/gleam/uri_test.gleam +++ b/test/gleam/uri_test.gleam @@ -1,9 +1,10 @@ +import gleam/uri +import gleam/should +import gleam/option.{None, Some} + if erlang { - import gleam/uri - import gleam/should import gleam/string import gleam/list - import gleam/option.{None, Some} pub fn full_parse_test() { assert Ok(parsed) = @@ -59,12 +60,85 @@ if erlang { "https://foo:bar@example.com:1234/path?query=true#fragment", ) } +} - pub fn path_only_uri_to_string_test() { - let test_uri = uri.Uri(None, None, None, None, "/", None, None) - should.equal(uri.to_string(test_uri), "/") - } +pub fn path_only_uri_to_string_test() { + uri.Uri(None, None, None, None, "/", None, None) + |> uri.to_string + |> should.equal("/") + + uri.Uri(None, None, None, None, "/teapot", None, None) + |> uri.to_string + |> should.equal("/teapot") + + uri.Uri(None, Some("user"), None, None, "/teapot", None, None) + |> uri.to_string + |> should.equal("/teapot") + + uri.Uri(None, None, None, None, "", None, None) + |> uri.to_string + |> should.equal("") +} + +pub fn scheme_to_string_test() { + uri.Uri(Some("ftp"), None, None, None, "thing.txt", None, None) + |> uri.to_string + |> should.equal("ftp:thing.txt") + + uri.Uri(Some("ftp"), None, None, None, "", None, None) + |> uri.to_string + |> should.equal("ftp:") + + uri.Uri(Some("ftp"), Some("ignored"), None, None, "", None, None) + |> uri.to_string + |> should.equal("ftp:") + + uri.Uri(Some("https"), None, None, None, "/one/two", None, None) + |> uri.to_string + |> should.equal("https:/one/two") +} +pub fn host_to_string_test() { + uri.Uri(Some("ftp"), None, Some("example.com"), None, "", None, None) + |> uri.to_string + |> should.equal("ftp://example.com/") + + uri.Uri(None, None, Some("example.com"), None, "", None, None) + |> uri.to_string + |> should.equal("//example.com/") + + uri.Uri(None, None, Some("example.com"), None, "/slash", None, None) + |> uri.to_string + |> should.equal("//example.com/slash") + + uri.Uri(None, None, Some("example.com"), None, "noslash", None, None) + |> uri.to_string + |> should.equal("//example.com/noslash") +} + +pub fn port_to_string_test() { + uri.Uri(Some("ftp"), None, Some("example.com"), Some(80), "", None, None) + |> uri.to_string + |> should.equal("ftp://example.com:80/") + + uri.Uri(None, None, Some("example.com"), Some(40), "", None, None) + |> uri.to_string + |> should.equal("//example.com:40/") + + uri.Uri(None, None, Some("example.com"), Some(80), "/slash", None, None) + |> uri.to_string + |> should.equal("//example.com:80/slash") + + uri.Uri(None, None, Some("example.com"), Some(81), "noslash", None, None) + |> uri.to_string + |> should.equal("//example.com:81/noslash") + + uri.Uri(None, None, None, Some(81), "noslash", None, None) + |> uri.to_string + |> should.equal("noslash") +} + +if erlang { pub fn parse_query_string_test() { assert Ok(parsed) = uri.parse_query("foo+bar=1&city=%C3%B6rebro") should.equal(parsed, [#("foo bar", "1"), #("city", "örebro")]) @@ -190,15 +264,15 @@ if erlang { pub fn origin_test() { assert Ok(parsed) = uri.parse("http://example.test/path?foo#bar") uri.origin(parsed) - |> should.equal(Ok("http://example.test")) + |> should.equal(Ok("http://example.test/")) assert Ok(parsed) = uri.parse("http://example.test:8080") uri.origin(parsed) - |> should.equal(Ok("http://example.test:8080")) + |> should.equal(Ok("http://example.test:8080/")) assert Ok(parsed) = uri.parse("https://example.test") uri.origin(parsed) - |> should.equal(Ok("https://example.test")) + |> should.equal(Ok("https://example.test/")) assert Ok(parsed) = uri.parse("http:///path") uri.origin(parsed) |