diff --git a/lib/url.dl b/lib/url.dl new file mode 100644 index 000000000..e39357012 --- /dev/null +++ b/lib/url.dl @@ -0,0 +1,95 @@ +/* Bindings for the Rust URL library. + */ + +extern type Url + +/* Parse an absolute URL from a string. */ +extern function url_parse(url: string): Result + +/* Parse a string as an URL, with this URL as the base URL. + * Note: a trailing slash is significant. Without it, the last + * path component is considered to be a “file” name to be removed + * to get at the “directory” that is used as the base */ +extern function join(url: Url, other: string): Result + +extern function url_to_string(url: Url): string +function to_string(url: Url): string { + url.url_to_string() +} + +/* Return the scheme of this URL, lower-cased, as an ASCII string without + * the ':' delimiter. */ +extern function scheme(url: Url): string + +/* Return whether the URL has an 'authority', which can contain a + * username, password, host, and port number. + * + * URLs that do not are either path-only like unix:/run/foo.socket or + * cannot-be-a-base like data:text/plain,Stuff. */ +extern function has_authority(url: Url): bool + +/* Return whether this URL is a cannot-be-a-base URL, meaning that parsing a + * relative URL string with this URL as the base will return an error. + * + * This is the case if the scheme and : delimiter are not followed by a / slash, + * as is typically the case of data: and mailto: URLs. */ +extern function cannot_be_a_base(url: Url): bool + +/* Return the username for this URL (typically the empty string) as a + * percent-encoded ASCII string. */ +extern function username(url: Url): string + +/* Return the password for this URL, if any, as a percent-encoded ASCII string. */ +extern function password(url: Url): Option + +/* Equivalent to url.host().is_some(). */ +extern function has_host(url: Url): bool + +/* Return the string representation of the host (domain or IP address) for + * this URL, if any. + * + * Non-ASCII domains are punycode-encoded per IDNA. IPv6 addresses are given + * between [ and ] brackets. + * + * Cannot-be-a-base URLs (typical of data: and mailto:) and some file: URLs + * don’t have a host. */ +extern function host_str(url: Url): Option + +/* If this URL has a host and it is a domain name (not an IP address), + * return it. */ +extern function domain(url: Url): Option + +/* Return the port number for this URL, if any. + * + * Note that default port numbers are never reflected by the serialization, + * use the port_or_known_default() method if you want a default port number + * returned. */ +extern function port(url: Url): Option + +/* Return the port number for this URL, or the default port number if it is + * known. + * + * This method only knows the default port number of the http, https, ws, wss, + * ftp, and gopher schemes. + * + * For URLs in these schemes, this method always returns Some(_). For other + * schemes, it is the same as Url::port(). + */ +extern function port_or_known_default(url: Url): Option + +/* Return the path for this URL, as a percent-encoded ASCII string. For + * cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with + * '/'. For other URLs, this starts with a '/' slash and continues with + * slash-separated path segments. */ +extern function path(url: Url): string + +/* Return this URL’s query string, if any, as a percent-encoded ASCII + * string. */ +extern function query(url: Url): Option + +/* Return this URL’s fragment identifier, if any. + * + * A fragment is the part of the URL after the # symbol. The fragment is + * optional and, if present, contains a fragment identifier that identifies + * a secondary resource, such as a section heading of a document. */ +extern function fragment(url: Url): Option diff --git a/lib/url.rs b/lib/url.rs new file mode 100644 index 000000000..5f23809ae --- /dev/null +++ b/lib/url.rs @@ -0,0 +1,104 @@ +use url; + +#[derive(Eq, Ord, Clone, Hash, PartialEq, PartialOrd, Serialize, Deserialize, Debug)] +pub struct url_Url { + url: url::Url, +} + +impl Default for url_Url { + fn default() -> Self { + url_Url { + url: url::Url::parse("http://127.0.0.1/").unwrap(), + } + } +} + +impl FromRecord for url_Url { + fn from_record(val: &record::Record) -> result::Result { + match (val) { + record::Record::String(s) => match (url::Url::parse(&s)) { + Ok(url) => Ok(url_Url { url }), + Err(e) => Err(format!("{}", e)), + }, + _ => Err(String::from("Unexpected type")), + } + } +} + +impl IntoRecord for url_Url { + fn into_record(self) -> record::Record { + record::Record::String(self.url.as_str().to_string()) + } +} + +impl record::Mutator for record::Record { + fn mutate(&self, t: &mut url_Url) -> result::Result<(), String> { + *t = url_Url::from_record(self)?; + Ok(()) + } +} + +pub fn url_url_parse(s: &String) -> std_Result { + match url::Url::parse(s) { + Ok(url) => std_Result::std_Ok { + res: url_Url { url }, + }, + Err(e) => std_Result::std_Err { + err: format!("{}", e), + }, + } +} + +pub fn url_join(url: &url_Url, other: &String) -> std_Result { + match url.url.join(other.as_str()) { + Ok(url) => std_Result::std_Ok { + res: url_Url { url }, + }, + Err(e) => std_Result::std_Err { + err: format!("{}", e), + }, + } +} + +pub fn url_url_to_string(url: &url_Url) -> String { + format!("{}", url.url) +} +pub fn url_scheme(url: &url_Url) -> String { + url.url.scheme().to_string() +} +pub fn url_has_authority(url: &url_Url) -> bool { + url.url.has_authority() +} +pub fn url_cannot_be_a_base(url: &url_Url) -> bool { + url.url.cannot_be_a_base() +} +pub fn url_username(url: &url_Url) -> String { + url.url.username().to_string() +} +pub fn url_password(url: &url_Url) -> std_Option { + option2std(url.url.password().map(|x| x.to_string())) +} +pub fn url_has_host(url: &url_Url) -> bool { + url.url.has_host() +} +pub fn url_host_str(url: &url_Url) -> std_Option { + option2std(url.url.host_str().map(|x| x.to_string())) +} +pub fn url_domain(url: &url_Url) -> std_Option { + option2std(url.url.domain().map(|x| x.to_string())) +} +pub fn url_port(url: &url_Url) -> std_Option { + option2std(url.url.port()) +} +pub fn url_port_or_known_default(url: &url_Url) -> std_Option { + option2std(url.url.port_or_known_default()) +} +pub fn url_path(url: &url_Url) -> String { + url.url.path().to_string() +} +pub fn url_query(url: &url_Url) -> std_Option { + option2std(url.url.query().map(|x| x.to_string())) +} +pub fn url_fragment(url: &url_Url) -> std_Option { + option2std(url.url.fragment().map(|x| x.to_string())) +} diff --git a/lib/url.toml b/lib/url.toml new file mode 100644 index 000000000..7d0112b24 --- /dev/null +++ b/lib/url.toml @@ -0,0 +1,3 @@ +[dependencies.url] +version = "2.1" +features = ["serde"] diff --git a/test/datalog_tests/lib_test.debug.ast.expected b/test/datalog_tests/lib_test.debug.ast.expected index 507f4e0fb..a59ce5307 100644 --- a/test/datalog_tests/lib_test.debug.ast.expected +++ b/test/datalog_tests/lib_test.debug.ast.expected @@ -103,6 +103,8 @@ typedef tinyset_test::Intersects = tinyset_test::Intersects{setid1: string, seti typedef tinyset_test::Intersects2 = tinyset_test::Intersects2{setid1: string, setid2: string, set: tinyset::Set64} typedef tinyset_test::SetElement = tinyset_test::SetElement{setid: string, element: std::u32} typedef tinyset_test::Sets = tinyset_test::Sets{setid: string, set: tinyset::Set64} +extern type url::Url +typedef url_test::URLTest = url_test::URLTest{description: string, val: string} typedef uuid::Error = string extern type uuid::Uuid typedef uuid_test::UUID = uuid_test::UUID{description: string, result: string} @@ -1046,6 +1048,26 @@ extern function tinyset::singleton (x: 'X): tinyset::Set64<'X> extern function tinyset::size (s: tinyset::Set64<'X>): bit<64> extern function tinyset::union (s1: tinyset::Set64<'X>, s2: tinyset::Set64<'X>): tinyset::Set64<'X> extern function tinyset::unions (sets: std::Vec>): tinyset::Set64<'X> +extern function url::cannot_be_a_base (url: url::Url): bool +extern function url::domain (url: url::Url): std::Option +extern function url::fragment (url: url::Url): std::Option +extern function url::has_authority (url: url::Url): bool +extern function url::has_host (url: url::Url): bool +extern function url::host_str (url: url::Url): std::Option +extern function url::join (url: url::Url, other: string): std::Result +extern function url::password (url: url::Url): std::Option +extern function url::path (url: url::Url): string +extern function url::port (url: url::Url): std::Option +extern function url::port_or_known_default (url: url::Url): std::Option +extern function url::query (url: url::Url): std::Option +extern function url::scheme (url: url::Url): string +function url::to_string (url: url::Url): string +{ + url::url_to_string(url) +} +extern function url::url_parse (url: string): std::Result +extern function url::url_to_string (url: url::Url): string +extern function url::username (url: url::Url): string extern function uuid::as_u128 (uuid: uuid::Uuid): std::u128 extern function uuid::from_bytes (b: std::Vec): std::Result extern function uuid::from_u128 (v: std::u128): uuid::Uuid @@ -1108,6 +1130,7 @@ output relation tinyset_test::Intersects [tinyset_test::Intersects] output relation tinyset_test::Intersects2 [tinyset_test::Intersects2] input relation tinyset_test::SetElement [tinyset_test::SetElement] output relation tinyset_test::Sets [tinyset_test::Sets] +output relation url_test::URLTest [url_test::URLTest] output relation uuid_test::UUID [uuid_test::UUID] std_test::SortedVector[(std_test::SortedVector{.v=sorted}: std_test::SortedVector)] :- std_test::Vector[(__std_test_vector0@ (std_test::Vector{.v=(v: std::Vec)}: std_test::Vector))], (var sorted: std::Vec) = (std::sort_imm(v): std::Vec), Inspect debug::debug_event((32'd0, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", __std_test_vector0, (std_test::SortedVector{.v=sorted}: std_test::SortedVector)). std_test::SortedVectorInPlace[(std_test::SortedVectorInPlace{.v=sorted}: std_test::SortedVectorInPlace)] :- std_test::Vector[(__std_test_vector0@ (std_test::Vector{.v=(v: std::Vec)}: std_test::Vector))], (var sorted: std::Vec) = ((var v2: std::Vec) = v; @@ -1413,4 +1436,45 @@ tinyset_test::Intersects[(tinyset_test::Intersects{.setid1=setid1, .setid2=setid set)), Inspect debug::debug_event((32'd288, 32'd2, 32'd0), ddlog_weight, ddlog_timestamp, "Condition", (setid1, set1, setid2, set2), (tinyset_test::Intersects{.setid1=setid1, .setid2=setid2, .set=set}: tinyset_test::Intersects)). tinyset_test::Intersects2[(tinyset_test::Intersects2{.setid1=setid1, .setid2=setid2, .set=(tinyset::intersection(set1, set2): tinyset::Set64)}: tinyset_test::Intersects2)] :- tinyset_test::Sets[(__tinyset_test_sets0@ (tinyset_test::Sets{.setid=(setid1: string), .set=(set1: tinyset::Set64)}: tinyset_test::Sets))], tinyset_test::Sets[(__tinyset_test_sets1@ (tinyset_test::Sets{.setid=(setid2: string), .set=(set2: tinyset::Set64)}: tinyset_test::Sets))], Inspect debug::debug_event_join((32'd289, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __tinyset_test_sets0, __tinyset_test_sets1, (tinyset_test::Intersects2{.setid1=setid1, .setid2=setid2, .set=(tinyset::intersection(set1, set2): tinyset::Set64)}: tinyset_test::Intersects2)). tinyset_test::Diffs[(tinyset_test::Diffs{.setid1=setid1, .setid2=setid2, .set=(tinyset::difference(set1, set2): tinyset::Set64)}: tinyset_test::Diffs)] :- tinyset_test::Sets[(__tinyset_test_sets0@ (tinyset_test::Sets{.setid=(setid1: string), .set=(set1: tinyset::Set64)}: tinyset_test::Sets))], tinyset_test::Sets[(__tinyset_test_sets1@ (tinyset_test::Sets{.setid=(setid2: string), .set=(set2: tinyset::Set64)}: tinyset_test::Sets))], Inspect debug::debug_event_join((32'd290, 32'd1, 32'd0), ddlog_weight, ddlog_timestamp, __tinyset_test_sets0, __tinyset_test_sets1, (tinyset_test::Diffs{.setid1=setid1, .setid2=setid2, .set=(tinyset::difference(set1, set2): tinyset::Set64)}: tinyset_test::Diffs)). +url_test::URLTest[(url_test::URLTest{.description="https://example.net", .val=url::to_string((std::unwrap_or_default(url::url_parse("https://example.net")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.net/a/b.html\".join(\"c.png\")", .val=url::to_string((std::unwrap_or_default(url::join((std::unwrap_or_default(url::url_parse("https://example.net/a/b.html")): url::Url), "c.png")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"file:///tmp/foo\".scheme()", .val=url::scheme((std::unwrap_or_default(url::url_parse("file:///tmp/foo")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".has_authority()", .val=std::to_string(url::has_authority((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"unix:/run/foo.socket\".has_authority()", .val=std::to_string(url::has_authority((std::unwrap_or_default(url::url_parse("unix:/run/foo.socket")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"data:text/plain,Stuff\".has_authority()", .val=std::to_string(url::has_authority((std::unwrap_or_default(url::url_parse("data:text/plain,Stuff")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".cannot_be_a_base()", .val=std::to_string(url::cannot_be_a_base((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"unix:/run/foo.socket\".cannot_be_a_base()", .val=std::to_string(url::cannot_be_a_base((std::unwrap_or_default(url::url_parse("unix:/run/foo.socket")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"data:text/plain,Stuff\".cannot_be_a_base()", .val=std::to_string(url::cannot_be_a_base((std::unwrap_or_default(url::url_parse("data:text/plain,Stuff")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".username()", .val=url::username((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://:secret123@example.com\".username()", .val=url::username((std::unwrap_or_default(url::url_parse("ftp://:secret123@example.com")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com\".username()", .val=url::username((std::unwrap_or_default(url::url_parse("https://example.com")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms:secret123@example.com\".password()", .val=(std::unwrap_or_default(url::password((std::unwrap_or_default(url::url_parse("ftp://rms:secret123@example.com")): url::Url))): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://:secret123@example.com\".password()", .val=(std::unwrap_or_default(url::password((std::unwrap_or_default(url::url_parse("ftp://:secret123@example.com")): url::Url))): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".password()", .val=(std::unwrap_or_default(url::password((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url))): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com\".password()", .val=(std::unwrap_or_default(url::password((std::unwrap_or_default(url::url_parse("https://example.com")): url::Url))): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".has_host()", .val=std::to_string(url::has_host((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"unix:/run/foo.socket\".has_host()", .val=std::to_string(url::has_host((std::unwrap_or_default(url::url_parse("unix:/run/foo.socket")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"data:text/plain,Stuff\".has_host()", .val=std::to_string(url::has_host((std::unwrap_or_default(url::url_parse("data:text/plain,Stuff")): url::Url)))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://127.0.0.1/index.html\".host_str()", .val=(std::unwrap_or(url::host_str((std::unwrap_or_default(url::url_parse("https://127.0.0.1/index.html")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".host_str()", .val=(std::unwrap_or(url::host_str((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"unix:/run/foo.socket\".host_str()", .val=(std::unwrap_or(url::host_str((std::unwrap_or_default(url::url_parse("unix:/run/foo.socket")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"data:text/plain,Stuff\".host_str()", .val=(std::unwrap_or(url::host_str((std::unwrap_or_default(url::url_parse("data:text/plain,Stuff")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://127.0.0.1/index.html\".domain()", .val=(std::unwrap_or(url::domain((std::unwrap_or_default(url::url_parse("https://127.0.0.1/index.html")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ftp://rms@example.com\".domain()", .val=(std::unwrap_or(url::domain((std::unwrap_or_default(url::url_parse("ftp://rms@example.com")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"unix:/run/foo.socket\".domain()", .val=(std::unwrap_or(url::domain((std::unwrap_or_default(url::url_parse("unix:/run/foo.socket")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"data:text/plain,Stuff\".domain()", .val=(std::unwrap_or(url::domain((std::unwrap_or_default(url::url_parse("data:text/plain,Stuff")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com\".port()", .val=std::to_string((std::unwrap_or_default(url::port((std::unwrap_or_default(url::url_parse("https://example.com")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com:443/\".port()", .val=std::to_string((std::unwrap_or_default(url::port((std::unwrap_or_default(url::url_parse("https://example.com:443/")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ssh://example.com:22\".port()", .val=std::to_string((std::unwrap_or_default(url::port((std::unwrap_or_default(url::url_parse("ssh://example.com:22")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com\".port_or_known_default()", .val=std::to_string((std::unwrap_or_default(url::port_or_known_default((std::unwrap_or_default(url::url_parse("https://example.com")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com:443/\".port_or_known_default()", .val=std::to_string((std::unwrap_or_default(url::port_or_known_default((std::unwrap_or_default(url::url_parse("https://example.com:443/")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"ssh://example.com:22\".port_or_known_default()", .val=std::to_string((std::unwrap_or_default(url::port_or_known_default((std::unwrap_or_default(url::url_parse("ssh://example.com:22")): url::Url))): bit<16>))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/api/versions?page=2\".path()", .val=url::path((std::unwrap_or_default(url::url_parse("https://example.com/api/versions?page=2")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com\".path()", .val=url::path((std::unwrap_or_default(url::url_parse("https://example.com")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/countries/vi\7879t nam\".path()", .val=url::path((std::unwrap_or_default(url::url_parse("https://example.com/countries/vi\7879t nam")): url::Url))}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/products?page=2\".query()", .val=(std::unwrap_or(url::query((std::unwrap_or_default(url::url_parse("https://example.com/products?page=2")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/products\".query()", .val=(std::unwrap_or(url::query((std::unwrap_or_default(url::url_parse("https://example.com/products")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/?country=espa\241ol\".query()", .val=(std::unwrap_or(url::query((std::unwrap_or_default(url::url_parse("https://example.com/?country=espa\241ol")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/data.csv#row=4\".fragment()", .val=(std::unwrap_or(url::fragment((std::unwrap_or_default(url::url_parse("https://example.com/data.csv#row=4")): url::Url)), ""): string)}: url_test::URLTest)]. +url_test::URLTest[(url_test::URLTest{.description="\"https://example.com/data.csv#cell=4,1-6,2\".fragment()", .val=(std::unwrap_or(url::fragment((std::unwrap_or_default(url::url_parse("https://example.com/data.csv#cell=4,1-6,2")): url::Url)), ""): string)}: url_test::URLTest)]. diff --git a/test/datalog_tests/lib_test.dl b/test/datalog_tests/lib_test.dl index 69499afa2..6a1fe6d77 100644 --- a/test/datalog_tests/lib_test.dl +++ b/test/datalog_tests/lib_test.dl @@ -6,3 +6,4 @@ import fp_test import regex_test import internment_test import tinyset_test +import url_test diff --git a/test/datalog_tests/test-libs.sh b/test/datalog_tests/test-libs.sh index ed9013192..651fa98d7 100755 --- a/test/datalog_tests/test-libs.sh +++ b/test/datalog_tests/test-libs.sh @@ -21,6 +21,7 @@ test_lib fp_test test_lib regex_test test_lib internment_test test_lib tinyset_test +test_lib url_test # No flatbuf support for Time, Date, etc yet FLATBUF=0 ./run-test.sh time_test.dl release diff --git a/test/datalog_tests/url_test.dat b/test/datalog_tests/url_test.dat new file mode 100644 index 000000000..1aaf5a18f --- /dev/null +++ b/test/datalog_tests/url_test.dat @@ -0,0 +1 @@ +dump url_test::URLTest; diff --git a/test/datalog_tests/url_test.dl b/test/datalog_tests/url_test.dl new file mode 100644 index 000000000..e6060e59d --- /dev/null +++ b/test/datalog_tests/url_test.dl @@ -0,0 +1,99 @@ +import url + +output relation URLTest(description: string, val: string) + +URLTest("https://example.net", url_parse("https://example.net").unwrap_or_default().to_string()). + +URLTest("\"https://example.net/a/b.html\".join(\"c.png\")", + url_parse("https://example.net/a/b.html").unwrap_or_default().join("c.png").unwrap_or_default().to_string()). + +URLTest("\"file:///tmp/foo\".scheme()", + url_parse("file:///tmp/foo").unwrap_or_default().scheme()). + +URLTest("\"ftp://rms@example.com\".has_authority()", + url_parse("ftp://rms@example.com").unwrap_or_default().has_authority().to_string()). +URLTest("\"unix:/run/foo.socket\".has_authority()", + url_parse("unix:/run/foo.socket").unwrap_or_default().has_authority().to_string()). +URLTest("\"data:text/plain,Stuff\".has_authority()", + url_parse("data:text/plain,Stuff").unwrap_or_default().has_authority().to_string()). + +URLTest("\"ftp://rms@example.com\".cannot_be_a_base()", + url_parse("ftp://rms@example.com").unwrap_or_default().cannot_be_a_base().to_string()). +URLTest("\"unix:/run/foo.socket\".cannot_be_a_base()", + url_parse("unix:/run/foo.socket").unwrap_or_default().cannot_be_a_base().to_string()). +URLTest("\"data:text/plain,Stuff\".cannot_be_a_base()", + url_parse("data:text/plain,Stuff").unwrap_or_default().cannot_be_a_base().to_string()). + +URLTest("\"ftp://rms@example.com\".username()", + url_parse("ftp://rms@example.com").unwrap_or_default().username()). +URLTest("\"ftp://:secret123@example.com\".username()", + url_parse("ftp://:secret123@example.com").unwrap_or_default().username()). +URLTest("\"https://example.com\".username()", + url_parse("https://example.com").unwrap_or_default().username()). + +URLTest("\"ftp://rms:secret123@example.com\".password()", + url_parse("ftp://rms:secret123@example.com").unwrap_or_default().password().unwrap_or_default()). +URLTest("\"ftp://:secret123@example.com\".password()", + url_parse("ftp://:secret123@example.com").unwrap_or_default().password().unwrap_or_default()). +URLTest("\"ftp://rms@example.com\".password()", + url_parse("ftp://rms@example.com").unwrap_or_default().password().unwrap_or_default()). +URLTest("\"https://example.com\".password()", + url_parse("https://example.com").unwrap_or_default().password().unwrap_or_default()). + +URLTest("\"ftp://rms@example.com\".has_host()", + url_parse("ftp://rms@example.com").unwrap_or_default().has_host().to_string()). +URLTest("\"unix:/run/foo.socket\".has_host()", + url_parse("unix:/run/foo.socket").unwrap_or_default().has_host().to_string()). +URLTest("\"data:text/plain,Stuff\".has_host()", + url_parse("data:text/plain,Stuff").unwrap_or_default().has_host().to_string()). + +URLTest("\"https://127.0.0.1/index.html\".host_str()", + url_parse("https://127.0.0.1/index.html").unwrap_or_default().host_str().unwrap_or("")). +URLTest("\"ftp://rms@example.com\".host_str()", + url_parse("ftp://rms@example.com").unwrap_or_default().host_str().unwrap_or("")). +URLTest("\"unix:/run/foo.socket\".host_str()", + url_parse("unix:/run/foo.socket").unwrap_or_default().host_str().unwrap_or("")). +URLTest("\"data:text/plain,Stuff\".host_str()", + url_parse("data:text/plain,Stuff").unwrap_or_default().host_str().unwrap_or("")). + +URLTest("\"https://127.0.0.1/index.html\".domain()", + url_parse("https://127.0.0.1/index.html").unwrap_or_default().domain().unwrap_or("")). +URLTest("\"ftp://rms@example.com\".domain()", + url_parse("ftp://rms@example.com").unwrap_or_default().domain().unwrap_or("")). +URLTest("\"unix:/run/foo.socket\".domain()", + url_parse("unix:/run/foo.socket").unwrap_or_default().domain().unwrap_or("")). +URLTest("\"data:text/plain,Stuff\".domain()", + url_parse("data:text/plain,Stuff").unwrap_or_default().domain().unwrap_or("")). + +URLTest("\"https://example.com\".port()", + url_parse("https://example.com").unwrap_or_default().port().unwrap_or_default().to_string()). +URLTest("\"https://example.com:443/\".port()", + url_parse("https://example.com:443/").unwrap_or_default().port().unwrap_or_default().to_string()). +URLTest("\"ssh://example.com:22\".port()", + url_parse("ssh://example.com:22").unwrap_or_default().port().unwrap_or_default().to_string()). + +URLTest("\"https://example.com\".port_or_known_default()", + url_parse("https://example.com").unwrap_or_default().port_or_known_default().unwrap_or_default().to_string()). +URLTest("\"https://example.com:443/\".port_or_known_default()", + url_parse("https://example.com:443/").unwrap_or_default().port_or_known_default().unwrap_or_default().to_string()). +URLTest("\"ssh://example.com:22\".port_or_known_default()", + url_parse("ssh://example.com:22").unwrap_or_default().port_or_known_default().unwrap_or_default().to_string()). + +URLTest("\"https://example.com/api/versions?page=2\".path()", + url_parse("https://example.com/api/versions?page=2").unwrap_or_default().path()). +URLTest("\"https://example.com\".path()", + url_parse("https://example.com").unwrap_or_default().path()). +URLTest("\"https://example.com/countries/việt nam\".path()", + url_parse("https://example.com/countries/việt nam").unwrap_or_default().path()). + +URLTest("\"https://example.com/products?page=2\".query()", + url_parse("https://example.com/products?page=2").unwrap_or_default().query().unwrap_or("")). +URLTest("\"https://example.com/products\".query()", + url_parse("https://example.com/products").unwrap_or_default().query().unwrap_or("")). +URLTest("\"https://example.com/?country=español\".query()", + url_parse("https://example.com/?country=español").unwrap_or_default().query().unwrap_or("")). + +URLTest("\"https://example.com/data.csv#row=4\".fragment()", + url_parse("https://example.com/data.csv#row=4").unwrap_or_default().fragment().unwrap_or("")). +URLTest("\"https://example.com/data.csv#cell=4,1-6,2\".fragment()", + url_parse("https://example.com/data.csv#cell=4,1-6,2").unwrap_or_default().fragment().unwrap_or("")). diff --git a/test/datalog_tests/url_test.dump.expected b/test/datalog_tests/url_test.dump.expected new file mode 100644 index 000000000..e8f42f530 --- /dev/null +++ b/test/datalog_tests/url_test.dump.expected @@ -0,0 +1,41 @@ +url_test::URLTest{.description = "\"data:text/plain,Stuff\".cannot_be_a_base()", .val = "true"} +url_test::URLTest{.description = "\"data:text/plain,Stuff\".domain()", .val = ""} +url_test::URLTest{.description = "\"data:text/plain,Stuff\".has_authority()", .val = "false"} +url_test::URLTest{.description = "\"data:text/plain,Stuff\".has_host()", .val = "false"} +url_test::URLTest{.description = "\"data:text/plain,Stuff\".host_str()", .val = ""} +url_test::URLTest{.description = "\"file:///tmp/foo\".scheme()", .val = "file"} +url_test::URLTest{.description = "\"ftp://:secret123@example.com\".password()", .val = "secret123"} +url_test::URLTest{.description = "\"ftp://:secret123@example.com\".username()", .val = ""} +url_test::URLTest{.description = "\"ftp://rms:secret123@example.com\".password()", .val = "secret123"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".cannot_be_a_base()", .val = "false"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".domain()", .val = "example.com"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".has_authority()", .val = "true"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".has_host()", .val = "true"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".host_str()", .val = "example.com"} +url_test::URLTest{.description = "\"ftp://rms@example.com\".password()", .val = ""} +url_test::URLTest{.description = "\"ftp://rms@example.com\".username()", .val = "rms"} +url_test::URLTest{.description = "\"https://127.0.0.1/index.html\".domain()", .val = ""} +url_test::URLTest{.description = "\"https://127.0.0.1/index.html\".host_str()", .val = "127.0.0.1"} +url_test::URLTest{.description = "\"https://example.com\".password()", .val = ""} +url_test::URLTest{.description = "\"https://example.com\".path()", .val = "/"} +url_test::URLTest{.description = "\"https://example.com\".port()", .val = "0"} +url_test::URLTest{.description = "\"https://example.com\".port_or_known_default()", .val = "443"} +url_test::URLTest{.description = "\"https://example.com\".username()", .val = ""} +url_test::URLTest{.description = "\"https://example.com/?country=español\".query()", .val = "country=espa%C3%B1ol"} +url_test::URLTest{.description = "\"https://example.com/api/versions?page=2\".path()", .val = "/api/versions"} +url_test::URLTest{.description = "\"https://example.com/countries/việt nam\".path()", .val = "/countries/vi%E1%BB%87t%20nam"} +url_test::URLTest{.description = "\"https://example.com/data.csv#cell=4,1-6,2\".fragment()", .val = "cell=4,1-6,2"} +url_test::URLTest{.description = "\"https://example.com/data.csv#row=4\".fragment()", .val = "row=4"} +url_test::URLTest{.description = "\"https://example.com/products\".query()", .val = ""} +url_test::URLTest{.description = "\"https://example.com/products?page=2\".query()", .val = "page=2"} +url_test::URLTest{.description = "\"https://example.com:443/\".port()", .val = "0"} +url_test::URLTest{.description = "\"https://example.com:443/\".port_or_known_default()", .val = "443"} +url_test::URLTest{.description = "\"https://example.net/a/b.html\".join(\"c.png\")", .val = "https://example.net/a/c.png"} +url_test::URLTest{.description = "\"ssh://example.com:22\".port()", .val = "22"} +url_test::URLTest{.description = "\"ssh://example.com:22\".port_or_known_default()", .val = "22"} +url_test::URLTest{.description = "\"unix:/run/foo.socket\".cannot_be_a_base()", .val = "false"} +url_test::URLTest{.description = "\"unix:/run/foo.socket\".domain()", .val = ""} +url_test::URLTest{.description = "\"unix:/run/foo.socket\".has_authority()", .val = "false"} +url_test::URLTest{.description = "\"unix:/run/foo.socket\".has_host()", .val = "false"} +url_test::URLTest{.description = "\"unix:/run/foo.socket\".host_str()", .val = ""} +url_test::URLTest{.description = "https://example.net", .val = "https://example.net/"}