diff options
Diffstat (limited to 'tests/unit.rs')
-rw-r--r-- | tests/unit.rs | 439 |
1 files changed, 438 insertions, 1 deletions
diff --git a/tests/unit.rs b/tests/unit.rs index 4c25198..13055a4 100644 --- a/tests/unit.rs +++ b/tests/unit.rs @@ -12,7 +12,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::net::{Ipv4Addr, Ipv6Addr}; use std::path::{Path, PathBuf}; -use url::{form_urlencoded, Host, Url}; +use url::{form_urlencoded, Host, Origin, Url}; #[test] fn size() { @@ -518,6 +518,209 @@ fn test_origin_hash() { } #[test] +fn test_origin_blob_equality() { + let origin = &Url::parse("http://example.net/").unwrap().origin(); + let blob_origin = &Url::parse("blob:http://example.net/").unwrap().origin(); + + assert_eq!(origin, blob_origin); +} + +#[test] +fn test_origin_opaque() { + assert!(!Origin::new_opaque().is_tuple()); + assert!(!&Url::parse("blob:malformed//").unwrap().origin().is_tuple()) +} + +#[test] +fn test_origin_unicode_serialization() { + let data = [ + ("http://π
.com", "http://π
.com"), + ("ftp://π
:π@π.com", "ftp://π.com"), + ("https://user@π
.com", "https://π
.com"), + ("http://π
.π:40", "http://π
.π:40"), + ]; + for &(unicode_url, expected_serialization) in &data { + let origin = Url::parse(unicode_url).unwrap().origin(); + assert_eq!(origin.unicode_serialization(), *expected_serialization); + } + + let ascii_origins = [ + Url::parse("http://example.net/").unwrap().origin(), + Url::parse("http://example.net:80/").unwrap().origin(), + Url::parse("http://example.net:81/").unwrap().origin(), + Url::parse("http://example.net").unwrap().origin(), + Url::parse("http://example.net/hello").unwrap().origin(), + Url::parse("https://example.net").unwrap().origin(), + Url::parse("ftp://example.net").unwrap().origin(), + Url::parse("file://example.net").unwrap().origin(), + Url::parse("http://user@example.net/").unwrap().origin(), + Url::parse("http://user:pass@example.net/") + .unwrap() + .origin(), + Url::parse("http://127.0.0.1").unwrap().origin(), + ]; + for ascii_origin in &ascii_origins { + assert_eq!( + ascii_origin.ascii_serialization(), + ascii_origin.unicode_serialization() + ); + } +} + +#[test] +fn test_socket_addrs() { + use std::net::ToSocketAddrs; + + let data = [ + ("https://127.0.0.1/", "127.0.0.1", 443), + ("https://127.0.0.1:9742/", "127.0.0.1", 9742), + ("custom-protocol://127.0.0.1:9742/", "127.0.0.1", 9742), + ("custom-protocol://127.0.0.1/", "127.0.0.1", 9743), + ("https://[::1]/", "::1", 443), + ("https://[::1]:9742/", "::1", 9742), + ("custom-protocol://[::1]:9742/", "::1", 9742), + ("custom-protocol://[::1]/", "::1", 9743), + ("https://localhost/", "localhost", 443), + ("https://localhost:9742/", "localhost", 9742), + ("custom-protocol://localhost:9742/", "localhost", 9742), + ("custom-protocol://localhost/", "localhost", 9743), + ]; + + for (url_string, host, port) in &data { + let url = url::Url::parse(url_string).unwrap(); + let addrs = url + .socket_addrs(|| match url.scheme() { + "custom-protocol" => Some(9743), + _ => None, + }) + .unwrap(); + assert_eq!( + Some(addrs[0]), + (*host, *port).to_socket_addrs().unwrap().next() + ); + } +} + +#[test] +fn test_no_base_url() { + let mut no_base_url = Url::parse("mailto:test@example.net").unwrap(); + + assert!(no_base_url.cannot_be_a_base()); + assert!(no_base_url.path_segments().is_none()); + assert!(no_base_url.path_segments_mut().is_err()); + assert!(no_base_url.set_host(Some("foo")).is_err()); + assert!(no_base_url + .set_ip_host("127.0.0.1".parse().unwrap()) + .is_err()); + + no_base_url.set_path("/foo"); + assert_eq!(no_base_url.path(), "%2Ffoo"); +} + +#[test] +fn test_domain() { + let url = Url::parse("https://127.0.0.1/").unwrap(); + assert_eq!(url.domain(), None); + + let url = Url::parse("mailto:test@example.net").unwrap(); + assert_eq!(url.domain(), None); + + let url = Url::parse("https://example.com/").unwrap(); + assert_eq!(url.domain(), Some("example.com")); +} + +#[test] +fn test_query() { + let url = Url::parse("https://example.com/products?page=2#fragment").unwrap(); + assert_eq!(url.query(), Some("page=2")); + assert_eq!( + url.query_pairs().next(), + Some((Cow::Borrowed("page"), Cow::Borrowed("2"))) + ); + + let url = Url::parse("https://example.com/products").unwrap(); + assert!(url.query().is_none()); + assert_eq!(url.query_pairs().count(), 0); + + let url = Url::parse("https://example.com/?country=espaΓ±ol").unwrap(); + assert_eq!(url.query(), Some("country=espa%C3%B1ol")); + assert_eq!( + url.query_pairs().next(), + Some((Cow::Borrowed("country"), Cow::Borrowed("espaΓ±ol"))) + ); + + let url = Url::parse("https://example.com/products?page=2&sort=desc").unwrap(); + assert_eq!(url.query(), Some("page=2&sort=desc")); + let mut pairs = url.query_pairs(); + assert_eq!(pairs.count(), 2); + assert_eq!( + pairs.next(), + Some((Cow::Borrowed("page"), Cow::Borrowed("2"))) + ); + assert_eq!( + pairs.next(), + Some((Cow::Borrowed("sort"), Cow::Borrowed("desc"))) + ); +} + +#[test] +fn test_fragment() { + let url = Url::parse("https://example.com/#fragment").unwrap(); + assert_eq!(url.fragment(), Some("fragment")); + + let url = Url::parse("https://example.com/").unwrap(); + assert_eq!(url.fragment(), None); +} + +#[test] +fn test_set_ip_host() { + let mut url = Url::parse("http://example.com").unwrap(); + + url.set_ip_host("127.0.0.1".parse().unwrap()).unwrap(); + assert_eq!(url.host_str(), Some("127.0.0.1")); + + url.set_ip_host("::1".parse().unwrap()).unwrap(); + assert_eq!(url.host_str(), Some("[::1]")); +} + +#[test] +fn test_set_href() { + use url::quirks::set_href; + + let mut url = Url::parse("https://existing.url").unwrap(); + + assert!(set_href(&mut url, "mal//formed").is_err()); + + assert!(set_href( + &mut url, + "https://user:pass@domain.com:9742/path/file.ext?key=val&key2=val2#fragment" + ) + .is_ok()); + assert_eq!( + url, + Url::parse("https://user:pass@domain.com:9742/path/file.ext?key=val&key2=val2#fragment") + .unwrap() + ); +} + +#[test] +fn test_domain_encoding_quirks() { + use url::quirks::{domain_to_ascii, domain_to_unicode}; + + let data = [ + ("http://example.com", "", ""), + ("π
.π", "xn--j28h.xn--938h", "π
.π"), + ("example.com", "example.com", "example.com"), + ("mailto:test@example.net", "", ""), + ]; + + for url in &data { + assert_eq!(domain_to_ascii(url.0), url.1); + assert_eq!(domain_to_unicode(url.0), url.2); + } +} + +#[test] fn test_windows_unc_path() { if !cfg!(windows) { return; @@ -582,6 +785,38 @@ fn test_syntax_violation_callback_lifetimes() { } #[test] +fn test_syntax_violation_callback_types() { + use url::SyntaxViolation::*; + + let data = [ + ("http://mozilla.org/\\foo", Backslash, "backslash"), + (" http://mozilla.org", C0SpaceIgnored, "leading or trailing control or space character are ignored in URLs"), + ("http://user:pass@mozilla.org", EmbeddedCredentials, "embedding authentication information (username or password) in an URL is not recommended"), + ("http:///mozilla.org", ExpectedDoubleSlash, "expected //"), + ("file:/foo.txt", ExpectedFileDoubleSlash, "expected // after file:"), + ("file://mozilla.org/c:/file.txt", FileWithHostAndWindowsDrive, "file: with host and Windows drive letter"), + ("http://mozilla.org/^", NonUrlCodePoint, "non-URL code point"), + ("http://mozilla.org/#\00", NullInFragment, "NULL characters are ignored in URL fragment identifiers"), + ("http://mozilla.org/%1", PercentDecode, "expected 2 hex digits after %"), + ("http://mozilla.org\t/foo", TabOrNewlineIgnored, "tabs or newlines are ignored in URLs"), + ("http://user@:pass@mozilla.org", UnencodedAtSign, "unencoded @ sign in username or password") + ]; + + for test_case in &data { + let violation = Cell::new(None); + Url::options() + .syntax_violation_callback(Some(&|v| violation.set(Some(v)))) + .parse(test_case.0) + .unwrap(); + + let v = violation.take(); + assert_eq!(v, Some(test_case.1)); + assert_eq!(v.unwrap().description(), test_case.2); + assert_eq!(v.unwrap().to_string(), test_case.2); + } +} + +#[test] fn test_options_reuse() { use url::SyntaxViolation::*; let violations = RefCell::new(Vec::new()); @@ -679,3 +914,205 @@ fn pop_if_empty_in_bounds() { segments.pop_if_empty(); segments.pop(); } + +#[test] +fn test_slicing() { + use url::Position::*; + + #[derive(Default)] + struct ExpectedSlices<'a> { + full: &'a str, + scheme: &'a str, + username: &'a str, + password: &'a str, + host: &'a str, + port: &'a str, + path: &'a str, + query: &'a str, + fragment: &'a str, + } + + let data = [ + ExpectedSlices { + full: "https://user:pass@domain.com:9742/path/file.ext?key=val&key2=val2#fragment", + scheme: "https", + username: "user", + password: "pass", + host: "domain.com", + port: "9742", + path: "/path/file.ext", + query: "key=val&key2=val2", + fragment: "fragment", + }, + ExpectedSlices { + full: "https://domain.com:9742/path/file.ext#fragment", + scheme: "https", + host: "domain.com", + port: "9742", + path: "/path/file.ext", + fragment: "fragment", + ..Default::default() + }, + ExpectedSlices { + full: "https://domain.com:9742/path/file.ext", + scheme: "https", + host: "domain.com", + port: "9742", + path: "/path/file.ext", + ..Default::default() + }, + ExpectedSlices { + full: "blob:blob-info", + scheme: "blob", + path: "blob-info", + ..Default::default() + }, + ]; + + for expected_slices in &data { + let url = Url::parse(expected_slices.full).unwrap(); + assert_eq!(&url[..], expected_slices.full); + assert_eq!(&url[BeforeScheme..AfterScheme], expected_slices.scheme); + assert_eq!( + &url[BeforeUsername..AfterUsername], + expected_slices.username + ); + assert_eq!( + &url[BeforePassword..AfterPassword], + expected_slices.password + ); + assert_eq!(&url[BeforeHost..AfterHost], expected_slices.host); + assert_eq!(&url[BeforePort..AfterPort], expected_slices.port); + assert_eq!(&url[BeforePath..AfterPath], expected_slices.path); + assert_eq!(&url[BeforeQuery..AfterQuery], expected_slices.query); + assert_eq!( + &url[BeforeFragment..AfterFragment], + expected_slices.fragment + ); + assert_eq!(&url[..AfterFragment], expected_slices.full); + } +} + +#[test] +fn test_make_relative() { + let tests = [ + ( + "http://127.0.0.1:8080/test", + "http://127.0.0.1:8080/test", + "", + ), + ( + "http://127.0.0.1:8080/test", + "http://127.0.0.1:8080/test/", + "test/", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test", + "../test", + ), + ( + "http://127.0.0.1:8080/", + "http://127.0.0.1:8080/?foo=bar#123", + "?foo=bar#123", + ), + ( + "http://127.0.0.1:8080/", + "http://127.0.0.1:8080/test/video", + "test/video", + ), + ( + "http://127.0.0.1:8080/test", + "http://127.0.0.1:8080/test/video", + "test/video", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test/video", + "video", + ), + ( + "http://127.0.0.1:8080/test", + "http://127.0.0.1:8080/test2/video", + "test2/video", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test2/video", + "../test2/video", + ), + ( + "http://127.0.0.1:8080/test/bla", + "http://127.0.0.1:8080/test2/video", + "../test2/video", + ), + ( + "http://127.0.0.1:8080/test/bla/", + "http://127.0.0.1:8080/test2/video", + "../../test2/video", + ), + ( + "http://127.0.0.1:8080/test/?foo=bar#123", + "http://127.0.0.1:8080/test/video", + "video", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test/video?baz=meh#456", + "video?baz=meh#456", + ), + ( + "http://127.0.0.1:8080/test", + "http://127.0.0.1:8080/test?baz=meh#456", + "?baz=meh#456", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test?baz=meh#456", + "../test?baz=meh#456", + ), + ( + "http://127.0.0.1:8080/test/", + "http://127.0.0.1:8080/test/?baz=meh#456", + "?baz=meh#456", + ), + ( + "http://127.0.0.1:8080/test/?foo=bar#123", + "http://127.0.0.1:8080/test/video?baz=meh#456", + "video?baz=meh#456", + ), + ]; + + for (base, uri, relative) in &tests { + let base_uri = url::Url::parse(base).unwrap(); + let relative_uri = url::Url::parse(uri).unwrap(); + let make_relative = base_uri.make_relative(&relative_uri).unwrap(); + assert_eq!( + make_relative, *relative, + "base: {}, uri: {}, relative: {}", + base, uri, relative + ); + assert_eq!( + base_uri.join(&relative).unwrap().as_str(), + *uri, + "base: {}, uri: {}, relative: {}", + base, + uri, + relative + ); + } + + let error_tests = [ + ("http://127.0.0.1:8080/", "https://127.0.0.1:8080/test/"), + ("http://127.0.0.1:8080/", "http://127.0.0.1:8081/test/"), + ("http://127.0.0.1:8080/", "http://127.0.0.2:8080/test/"), + ("mailto:a@example.com", "mailto:b@example.com"), + ]; + + for (base, uri) in &error_tests { + let base_uri = url::Url::parse(base).unwrap(); + let relative_uri = url::Url::parse(uri).unwrap(); + let make_relative = base_uri.make_relative(&relative_uri); + assert_eq!(make_relative, None, "base: {}, uri: {}", base, uri); + } +} |