219 lines
6.9 KiB
Rust
219 lines
6.9 KiB
Rust
|
|
//! 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:?}"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|