//! Tests for normalization.
mod components;
#[macro_use]
mod utils;
#[cfg(feature = "alloc")]
use iri_string::format::ToDedicatedString;
use iri_string::types::*;
use self::components::TEST_CASES;
/// Semantically different IRIs should not be normalized into the same IRI.
#[test]
fn different_iris() {
for case in TEST_CASES
.iter()
.filter(|case| !case.different_iris.is_empty())
{
let normalized = IriStr::new(case.normalized_iri).expect("should be valid IRI reference");
for other in case.different_iris.iter().copied() {
let other = IriStr::new(other).expect("should be valid IRI reference");
assert_ne!(
normalized, other,
"<{}> should not be normalized to <{other}>, case={case:#?}",
case.composed
);
}
}
}
/// Normalization should work for IRI.
#[test]
fn normalize_uri() {
for case in TEST_CASES
.iter()
.filter(|case| case.is_uri_class() && case.is_absolute())
{
let source = UriStr::new(case.composed).expect("should be valid URI");
let normalized = source.normalize();
let expected = UriStr::new(case.normalized_uri).expect("should be valid URI");
assert_eq_display!(normalized, expected, "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_string(), expected.as_str(), "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_dedicated_string(), expected, "case={case:#?}");
assert_eq!(
case.is_rfc3986_normalizable(),
normalized.ensure_rfc3986_normalizable().is_ok(),
"case={case:#?}"
);
}
}
/// Normalization should work for IRI.
#[test]
fn normalize_iri() {
for case in TEST_CASES
.iter()
.filter(|case| case.is_iri_class() && case.is_absolute())
{
let source = IriStr::new(case.composed).expect("should be valid IRI");
let normalized = source.normalize();
let expected = IriStr::new(case.normalized_iri).expect("should be valid IRI");
assert_eq_display!(normalized, expected, "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_string(), expected.as_str(), "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_dedicated_string(), expected, "case={case:#?}");
assert_eq!(
case.is_rfc3986_normalizable(),
normalized.ensure_rfc3986_normalizable().is_ok(),
"case={case:#?}"
);
}
}
/// WHATWG-like normalization should work for IRI.
#[test]
fn normalize_uri_whatwg_like() {
for case in TEST_CASES
.iter()
.filter(|case| case.is_uri_class() && case.is_absolute())
{
let source = UriStr::new(case.composed).expect("should be valid URI");
let normalized = source.normalize_but_preserve_authorityless_relative_path();
let expected = UriStr::new(
case.normalized_uri_whatwg_like
.unwrap_or(case.normalized_uri),
)
.expect("should be valid URI");
assert_eq_display!(normalized, expected, "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_string(), expected.as_str(), "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_dedicated_string(), expected, "case={case:#?}");
assert_eq!(
case.is_rfc3986_normalizable(),
normalized.ensure_rfc3986_normalizable().is_ok(),
"case={case:#?}"
);
}
}
/// WHATWG-like normalization should work for IRI.
#[test]
fn normalize_iri_whatwg_like() {
for case in TEST_CASES
.iter()
.filter(|case| case.is_iri_class() && case.is_absolute())
{
let source = IriStr::new(case.composed).expect("should be valid IRI");
let normalized = source.normalize_but_preserve_authorityless_relative_path();
let expected = IriStr::new(
case.normalized_iri_whatwg_like
.unwrap_or(case.normalized_iri),
)
.expect("should be valid IRI");
assert_eq_display!(normalized, expected, "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_string(), expected.as_str(), "case={case:#?}");
#[cfg(feature = "alloc")]
assert_eq!(normalized.to_dedicated_string(), expected, "case={case:#?}");
assert_eq!(
case.is_rfc3986_normalizable(),
normalized.ensure_rfc3986_normalizable().is_ok(),
"case={case:#?}"
);
}
}
/// Normalization should be idempotent.
#[test]
fn normalize_idempotent() {
let mut buf = [0_u8; 512];
for case in TEST_CASES
.iter()
.filter(|case| case.is_iri_class() && case.is_absolute())
{
let source = IriStr::new(case.composed).expect("should be valid IRI");
let normalized = source.normalize();
let expected = IriStr::new(case.normalized_iri).expect("should be valid IRI");
let normalized_s =
iri_string::format::write_to_slice(&mut buf, &normalized).expect("not enough buffer");
let normalized_s = IriStr::new(normalized_s).expect("should be valid IRI reference");
// Normalize again.
let normalized_again = normalized_s.normalize();
assert_eq_display!(normalized_again, expected, "case={case:#?}");
}
}
/// Normalizedness checks.
#[test]
fn normalizedness() {
#[derive(Debug, Clone, Copy)]
struct Case {
iri: &'static str,
is_normalized_default: bool,
is_normalized_rfc3986: bool,
is_normalized_whatwg_like: bool,
}
const CASES: &[Case] = &[
Case {
iri: "scheme:/.//foo",
is_normalized_default: true,
is_normalized_rfc3986: false,
is_normalized_whatwg_like: true,
},
Case {
iri: "scheme:.///foo",
is_normalized_default: false,
is_normalized_rfc3986: false,
is_normalized_whatwg_like: true,
},
Case {
iri: "scheme://authority/.//foo",
is_normalized_default: false,
is_normalized_rfc3986: false,
is_normalized_whatwg_like: false,
},
Case {
iri: "scheme:relative/..//foo",
is_normalized_default: false,
is_normalized_rfc3986: false,
is_normalized_whatwg_like: true,
},
];
for case in CASES {
let iri = IriStr::new(case.iri).expect("should be valid IRI");
assert_eq!(
iri.is_normalized(),
case.is_normalized_default,
"case={case:?}"
);
assert_eq!(
iri.is_normalized_rfc3986(),
case.is_normalized_rfc3986,
"case={case:?}"
);
assert_eq!(
iri.is_normalized_but_authorityless_relative_path_preserved(),
case.is_normalized_whatwg_like,
"case={case:?}"
);
}
}