use super::parse_graceful;
use crate::Protocol;
use crate::address::{Authority, Domain, Host, HostWithOptPort, UserInfo};
use crate::uri::{PathRef, Uri};
#[test]
fn set_path_replaces_lazy_path() {
let mut uri: Uri = parse_graceful("/old").unwrap();
uri.set_path("/new");
assert_eq!(uri.to_string(), "/new");
}
#[test]
fn set_path_preserves_query_and_fragment() {
let mut uri: Uri = parse_graceful("/old?q=1#frag").unwrap();
uri.set_path("/new");
assert_eq!(uri.to_string(), "/new?q=1#frag");
}
#[test]
fn set_path_accepts_empty() {
let mut uri: Uri = parse_graceful("https://example.com/x").unwrap();
uri.set_path("");
assert_eq!(uri.to_string(), "https://example.com");
}
#[test]
fn set_path_auto_encodes_query_and_fragment_bytes() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_path("/foo?bar");
assert_eq!(uri.to_string(), "/foo%3Fbar");
uri.set_path("/foo#frag");
assert_eq!(uri.to_string(), "/foo%23frag");
}
#[test]
fn set_path_auto_encodes_controls_and_non_ascii() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_path("/foo\nbar");
assert_eq!(uri.to_string(), "/foo%0Abar");
uri.set_path("/foo\0bar");
assert_eq!(uri.to_string(), "/foo%00bar");
uri.set_path("/caf\u{e9}");
assert_eq!(uri.to_string(), "/caf%C3%A9");
}
#[test]
fn set_path_passes_pchar_and_slash_through() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_path("/a/b/c-d.e_f~g!h$i&j'k(l)m*n+o,p;q=r:s@t/0123");
assert_eq!(
uri.to_string(),
"/a/b/c-d.e_f~g!h$i&j'k(l)m*n+o,p;q=r:s@t/0123",
);
}
#[test]
fn set_path_accepts_typed_path_ref_as_encoded_component_input() {
let path = PathRef::from_raw_str("/a b/%2F/%zz/%A");
let mut uri: Uri = parse_graceful("https://example.com/old").unwrap();
uri.set_path(path);
assert_eq!(uri.to_string(), "https://example.com/a%20b/%2F/%25zz/%25A");
}
#[test]
fn with_path_consumes_and_returns() {
let uri = parse_graceful("/old").unwrap().with_path("/new");
assert_eq!(uri.to_string(), "/new");
}
#[test]
fn with_additional_path_segment_appends() {
let uri = parse_graceful("https://example.com").unwrap();
assert_eq!(
uri.with_additional_path_segment("v1").to_string(),
"https://example.com/v1",
);
let uri = parse_graceful("https://example.com/foo").unwrap();
assert_eq!(
uri.with_additional_path_segment("bar").to_string(),
"https://example.com/foo/bar",
);
let uri = parse_graceful("https://example.com/foo/").unwrap();
assert_eq!(
uri.with_additional_path_segment("bar").to_string(),
"https://example.com/foo/bar",
);
}
#[test]
fn set_additional_path_segment_chains_in_place() {
let mut uri = parse_graceful("https://example.com").unwrap();
uri.set_additional_path_segment("v1")
.set_additional_path_segment("users");
assert_eq!(uri.to_string(), "https://example.com/v1/users");
}
#[test]
fn additional_path_segment_encodes_like_push_segment() {
let uri = parse_graceful("/p").unwrap();
assert_eq!(
uri.with_additional_path_segment("a/b").to_string(),
"/p/a%2Fb",
);
let uri = parse_graceful("/p").unwrap();
assert_eq!(
uri.with_additional_path_segment("caf\u{e9}").to_string(),
"/p/caf%C3%A9",
);
}
#[test]
fn additional_path_segments_respects_path_boundaries() {
let uri = parse_graceful("/p").unwrap();
assert_eq!(
uri.with_additional_path_segments("a/b").to_string(),
"/p/a/b",
);
let uri = parse_graceful("/p").unwrap();
assert_eq!(
uri.with_additional_path_segments("caf\u{e9}/b").to_string(),
"/p/caf%C3%A9/b",
);
}
#[test]
fn additional_path_segment_on_asterisk_drops_asterisk() {
let mut uri = parse_graceful("*").unwrap();
assert!(uri.is_asterisk());
uri.set_additional_path_segment("x");
assert!(!uri.is_asterisk());
assert_eq!(uri.to_string(), "/x");
}
#[test]
fn path_without_last_segment_pops_one_wire_segment() {
let uri = parse_graceful("https://example.com/foo/bar").unwrap();
assert_eq!(
uri.with_path_without_last_segment().to_string(),
"https://example.com/foo",
);
let uri = parse_graceful("https://example.com/foo/bar/").unwrap();
assert_eq!(
uri.with_path_without_last_segment().to_string(),
"https://example.com/foo/bar",
);
let uri = parse_graceful("/foo").unwrap();
assert_eq!(uri.with_path_without_last_segment().to_string(), "");
}
#[test]
fn set_path_without_last_segment_in_place_and_round_trips_push() {
let mut uri = parse_graceful("https://example.com/v1").unwrap();
uri.set_additional_path_segment("users")
.set_path_without_last_segment();
assert_eq!(uri.to_string(), "https://example.com/v1");
}
#[test]
fn path_without_last_segment_on_empty_is_noop() {
let uri = parse_graceful("https://example.com").unwrap();
assert_eq!(
uri.with_path_without_last_segment().to_string(),
"https://example.com",
);
}
#[test]
fn set_query_replaces_and_adds() {
let mut uri: Uri = parse_graceful("/p?old=1").unwrap();
uri.set_query_from_bytes("new=2");
assert_eq!(uri.to_string(), "/p?new=2");
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("a=1");
assert_eq!(uri.to_string(), "/p?a=1");
}
#[test]
fn set_query_empty_preserves_question_mark() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("");
assert_eq!(uri.to_string(), "/p?");
}
#[test]
fn set_query_auto_encodes_hash() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("a=1#frag");
assert_eq!(uri.to_string(), "/p?a=1%23frag");
}
#[test]
fn set_query_auto_encodes_controls_and_non_ascii() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("a=\n");
assert_eq!(uri.to_string(), "/p?a=%0A");
uri.set_query_from_bytes("city=caf\u{e9}");
assert_eq!(uri.to_string(), "/p?city=caf%C3%A9");
}
#[test]
fn set_query_passes_query_grammar_through() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("a=1&b=2/3?4");
assert_eq!(uri.to_string(), "/p?a=1&b=2/3?4");
}
#[test]
fn set_query_encodes_truncated_percent_triplet() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_query_from_bytes("x=%A");
assert_eq!(uri.to_string(), "/p?x=%25A");
}
#[test]
fn unset_query_removes_question_mark() {
let mut uri: Uri = parse_graceful("/p?a=1").unwrap();
uri.unset_query();
assert_eq!(uri.to_string(), "/p");
assert!(uri.query().is_none());
}
#[test]
fn without_query_consumes_and_removes() {
let uri = parse_graceful("/p?a=1").unwrap().without_query();
assert_eq!(uri.to_string(), "/p");
}
#[test]
fn set_fragment_replaces_and_empty_preserves_hash() {
let mut uri: Uri = parse_graceful("/p#old").unwrap();
uri.set_fragment("new");
assert_eq!(uri.to_string(), "/p#new");
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_fragment("");
assert_eq!(uri.to_string(), "/p#");
}
#[test]
fn set_fragment_auto_encodes_controls_and_non_ascii() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_fragment("sec\n");
assert_eq!(uri.to_string(), "/p#sec%0A");
}
#[test]
fn set_fragment_encodes_truncated_percent_triplet() {
let mut uri: Uri = parse_graceful("/p").unwrap();
uri.set_fragment("frag%A");
assert_eq!(uri.to_string(), "/p#frag%25A");
}
#[test]
fn unset_and_without_fragment() {
let mut uri: Uri = parse_graceful("/p#section").unwrap();
uri.unset_fragment();
assert_eq!(uri.to_string(), "/p");
let uri = parse_graceful("/p#section").unwrap().without_fragment();
assert_eq!(uri.to_string(), "/p");
}
#[test]
fn scheme_set_unset_with_without_and_maybe() {
let mut uri: Uri = parse_graceful("http://example.com/").unwrap();
uri.set_scheme(Protocol::HTTPS);
assert_eq!(uri.to_string(), "https://example.com/");
uri.unset_scheme();
assert_eq!(uri.to_string(), "//example.com/");
let uri = parse_graceful("//example.com/p")
.unwrap()
.with_scheme(Protocol::HTTPS);
assert_eq!(uri.to_string(), "https://example.com/p");
let uri = uri.without_scheme();
assert_eq!(uri.to_string(), "//example.com/p");
let uri = uri.maybe_with_scheme(Some(Protocol::HTTP));
assert_eq!(uri.to_string(), "http://example.com/p");
let uri = uri.maybe_with_scheme(None);
assert_eq!(uri.to_string(), "//example.com/p");
}
#[test]
fn authority_set_unset_with_without() {
let mut uri: Uri = parse_graceful("https://old.com/p").unwrap();
uri.set_authority(Authority {
user_info: None,
address: HostWithOptPort {
host: Host::Name(Domain::try_from("new.com").unwrap()),
port: crate::address::OptPort::Set(8080),
},
});
assert_eq!(uri.to_string(), "https://new.com:8080/p");
uri.unset_authority();
assert_eq!(uri.to_string(), "https:/p");
}
#[test]
fn set_authority_with_userinfo_on_origin_form() {
let uri = parse_graceful("/p")
.unwrap()
.with_authority(Authority {
user_info: Some(UserInfo::try_from("u:p").unwrap()),
address: HostWithOptPort {
host: Host::Name(Domain::try_from("api.example.com").unwrap()),
port: crate::address::OptPort::Unset,
},
})
.with_scheme(Protocol::HTTPS);
assert_eq!(uri.to_string(), "https://u:p@api.example.com/p");
}
#[test]
fn set_path_on_asterisk_drops_asterisk() {
let mut uri: Uri = parse_graceful("*").unwrap();
assert!(uri.is_asterisk());
uri.set_path("/x");
assert!(!uri.is_asterisk());
assert_eq!(uri.to_string(), "/x");
}
#[test]
fn set_scheme_on_asterisk_drops_asterisk() {
let mut uri: Uri = parse_graceful("*").unwrap();
assert!(uri.is_asterisk());
uri.set_scheme(crate::Protocol::HTTP);
assert!(!uri.is_asterisk());
assert!(uri.scheme().is_some());
}
#[test]
fn set_fragment_on_asterisk_drops_asterisk() {
let mut uri: Uri = parse_graceful("*").unwrap();
uri.set_fragment("frag");
assert!(!uri.is_asterisk());
assert!(uri.fragment().is_some());
}
#[test]
fn set_query_from_bytes_on_asterisk_drops_asterisk() {
let mut uri: Uri = parse_graceful("*").unwrap();
uri.set_query_from_bytes("a=1");
assert!(!uri.is_asterisk());
assert!(uri.query().is_some());
}
#[test]
fn set_host_on_asterisk_drops_asterisk() {
let mut uri: Uri = parse_graceful("*").unwrap();
uri.set_host(crate::address::Domain::from_static("example.com"));
assert!(!uri.is_asterisk());
assert_eq!(uri.host().unwrap().to_str(), "example.com");
}
#[test]
fn chained_setters() {
let mut uri: Uri = parse_graceful("/").unwrap();
uri.set_path("/v2/users")
.set_query_from_bytes("page=2")
.set_fragment("results");
assert_eq!(uri.to_string(), "/v2/users?page=2#results");
}
#[test]
fn fluent_with_chain() {
let uri = parse_graceful("/")
.unwrap()
.with_path("/v2/users")
.with_query_from_bytes("page=2")
.with_fragment("results");
assert_eq!(uri.to_string(), "/v2/users?page=2#results");
}
#[test]
fn second_mutation_does_not_re_promote() {
let mut uri: Uri = parse_graceful("/p?a=1").unwrap();
uri.set_path("/q");
uri.set_query_from_bytes("b=2");
assert_eq!(uri.to_string(), "/q?b=2");
}
#[test]
fn mutation_preserves_userinfo_round_trip() {
let mut uri: Uri = parse_graceful("https://user:pw@example.com/old").unwrap();
uri.set_path("/new");
assert_eq!(uri.to_string(), "https://user:pw@example.com/new");
assert_eq!(uri.userinfo().unwrap().as_str(), "user:pw");
}
#[test]
fn clone_after_mutation_is_independent() {
let mut a: Uri = parse_graceful("/p?a=1").unwrap();
a.set_path("/q");
let b = a.clone();
a.set_path("/r");
assert_eq!(a.to_string(), "/r?a=1");
assert_eq!(b.to_string(), "/q?a=1");
}
#[test]
fn set_path_with_legal_string_moves_into_storage() {
let mut uri: Uri = parse_graceful("/").unwrap();
let s = "/some/legal/path".repeat(200); let s_ptr = s.as_ptr();
uri.set_path(s);
let encoded = uri.path().unwrap().as_encoded_str();
let new_ptr = encoded.as_ptr();
assert_eq!(
s_ptr, new_ptr,
"Legal owned input should have moved without copying",
);
}
#[test]
fn set_path_with_encodable_string_allocates_new_buffer() {
let mut uri: Uri = parse_graceful("/").unwrap();
let s = String::from("/hello world");
uri.set_path(s);
assert_eq!(uri.to_string(), "/hello%20world");
}
#[test]
fn set_port_replaces_explicit_port() {
let mut uri: Uri = parse_graceful("https://example.com:443/p").unwrap();
uri.set_port(8080);
assert_eq!(uri.port_u16(), Some(8080));
assert_eq!(uri.to_string(), "https://example.com:8080/p");
}
#[test]
fn set_port_clears_via_none() {
let mut uri: Uri = parse_graceful("https://example.com:443/p").unwrap();
uri.set_port(None);
assert!(uri.port().is_unset());
assert_eq!(uri.to_string(), "https://example.com/p");
}
#[test]
fn set_port_unset_clears() {
let mut uri: Uri = parse_graceful("https://example.com:443/p").unwrap();
uri.set_port(crate::address::OptPort::Unset);
assert!(uri.port().is_unset());
}
#[test]
fn with_port_consuming_form() {
let uri = parse_graceful("https://example.com/p")
.unwrap()
.with_port(9000);
assert_eq!(uri.port_u16(), Some(9000));
}
#[test]
fn unset_port_clears_port_and_preserves_rest() {
let mut uri: Uri = parse_graceful("http://user@example.com:8080/p?q=1").unwrap();
uri.unset_port();
assert!(uri.port().is_unset());
assert_eq!(uri.to_string(), "http://user@example.com/p?q=1");
uri.unset_port();
assert_eq!(uri.to_string(), "http://user@example.com/p?q=1");
}
#[test]
fn unset_port_clears_wire_only_empty_port() {
let mut uri: Uri = parse_graceful("http://example.com:/p").unwrap();
uri.unset_port();
assert!(uri.port().is_unset());
assert_eq!(uri.to_string(), "http://example.com/p");
}
#[test]
fn unset_port_without_authority_is_noop() {
let mut uri: Uri = parse_graceful("/p?q=1").unwrap();
uri.unset_port();
assert!(uri.authority().is_none());
assert_eq!(uri.to_string(), "/p?q=1");
}
#[test]
fn without_port_consuming_form() {
let uri = parse_graceful("https://example.com:9000/p")
.unwrap()
.without_port();
assert!(uri.port().is_unset());
assert_eq!(uri.to_string(), "https://example.com/p");
}
#[test]
fn set_userinfo_replaces_userinfo() {
let mut uri: Uri = parse_graceful("https://example.com/p").unwrap();
let ui = UserInfo::from_static("alice:secret");
uri.set_user_info(ui);
assert!(uri.userinfo().is_some());
assert_eq!(uri.to_string(), "https://alice:secret@example.com/p");
}
#[test]
fn set_userinfo_clears_via_none() {
let mut uri: Uri = parse_graceful("https://alice:secret@example.com/p").unwrap();
uri.set_user_info(None);
assert!(uri.userinfo().is_none());
assert_eq!(uri.to_string(), "https://example.com/p");
}
#[test]
fn try_set_userinfo_accepts_str() {
let mut uri: Uri = parse_graceful("https://example.com/p").unwrap();
uri.try_set_user_info("alice").unwrap();
assert_eq!(uri.to_string(), "https://alice@example.com/p");
}
#[test]
fn try_set_userinfo_rejects_invalid_input() {
let mut uri: Uri = parse_graceful("https://example.com/p").unwrap();
let err = uri.try_set_user_info("bad@user").unwrap_err();
match err {
crate::uri::UriError::ComponentConversion { component, .. } => {
assert_eq!(component, crate::uri::Component::UserInfo);
}
other => panic!("expected ComponentConversion(UserInfo), got {other:?}"),
}
}
#[test]
fn try_with_user_info_consuming_form_success() {
let uri: Uri = parse_graceful("https://example.com/p").unwrap();
let uri = uri.try_with_user_info("alice").unwrap();
assert_eq!(uri.to_string(), "https://alice@example.com/p");
}
#[test]
fn try_with_user_info_consuming_form_error() {
let uri: Uri = parse_graceful("https://example.com/p").unwrap();
let err = uri.try_with_user_info("bad@user").unwrap_err();
match err {
crate::uri::UriError::ComponentConversion { component, .. } => {
assert_eq!(component, crate::uri::Component::UserInfo);
}
other => panic!("expected ComponentConversion(UserInfo), got {other:?}"),
}
}
#[test]
fn set_scheme_replaces_scheme() {
let mut uri: Uri = parse_graceful("http://example.com/p").unwrap();
uri.set_scheme(Protocol::HTTPS);
assert_eq!(uri.to_string(), "https://example.com/p");
}
#[test]
fn unset_scheme_yields_relative_reference() {
let mut uri: Uri = parse_graceful("https://example.com/p").unwrap();
uri.unset_scheme();
assert!(uri.scheme().is_none());
}
#[test]
fn maybe_set_scheme_accepts_some_or_none() {
let mut uri: Uri = parse_graceful("http://example.com/p").unwrap();
uri.maybe_set_scheme(Some(Protocol::WSS));
assert_eq!(uri.scheme(), Some(&Protocol::WSS));
uri.maybe_set_scheme(None);
assert!(uri.scheme().is_none());
}