".repeat(35_000));
}
#[test]
fn included_angles() {
let fragment = "1 < 2";
let result = clean(fragment);
assert_eq!(result, "1 < 2");
}
#[test]
fn remove_script() {
let fragment = "an example";
let result = clean(fragment);
assert_eq!(result, "an example");
}
#[test]
fn ignore_link() {
let fragment = "a good example";
let expected = "a \
good example";
let result = clean(fragment);
assert_eq!(result, expected);
}
#[test]
fn remove_unsafe_link() {
let fragment = "an evil example";
let result = clean(fragment);
assert_eq!(
result,
"an evil example"
);
}
#[test]
fn remove_js_link() {
let fragment = "an evil example";
let result = clean(fragment);
assert_eq!(result, "an evil example");
}
#[test]
fn tag_rebalance() {
let fragment = "AWESOME!";
let result = clean(fragment);
assert_eq!(result, "AWESOME!");
}
#[test]
fn allow_url_relative() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::PassThrough)
.clean(fragment)
.to_string();
assert_eq!(
result,
"Test"
);
}
#[test]
fn rewrite_url_relative() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::RewriteWithBase(
Url::parse("http://example.com/").unwrap(),
))
.clean(fragment)
.to_string();
assert_eq!(
result,
"Test"
);
}
#[test]
fn rewrite_url_relative_with_invalid_url() {
// Reduced from https://github.com/Bauke/ammonia-crash-test
let fragment = r##"test"##;
let result = Builder::new()
.url_relative(UrlRelative::RewriteWithBase(
Url::parse("http://example.com/").unwrap(),
))
.clean(fragment)
.to_string();
assert_eq!(result, r##"test"##);
}
#[test]
fn attribute_filter_nop() {
let fragment = "Test";
let result = Builder::new()
.attribute_filter(|elem, attr, value| {
assert_eq!("a", elem);
assert!(
match (attr, value) {
("href", "test") => true,
("rel", "noopener noreferrer") => true,
_ => false,
},
"{}",
value.to_string()
);
Some(value.into())
})
.clean(fragment)
.to_string();
assert_eq!(
result,
"Test"
);
}
#[test]
fn attribute_filter_drop() {
let fragment = "Test";
let result = Builder::new()
.attribute_filter(|elem, attr, value| {
assert_eq!("img", elem);
match (attr, value) {
("src", "imgtest") => None,
("alt", "test") => Some(value.into()),
_ => panic!("unexpected"),
}
})
.clean(fragment)
.to_string();
assert_eq!(result, r#"Test"#);
}
#[test]
fn url_filter_absolute() {
let fragment = "Test";
let result = Builder::new()
.attribute_filter(|elem, attr, value| {
assert_eq!("img", elem);
match (attr, value) {
("src", "imgtest") => {
Some(format!("https://example.com/images/{}", value).into())
}
("alt", "test") => None,
_ => panic!("unexpected"),
}
})
.url_relative(UrlRelative::RewriteWithBase(
Url::parse("http://wrong.invalid/").unwrap(),
))
.clean(fragment)
.to_string();
assert_eq!(
result,
r#"Test"#
);
}
#[test]
fn url_filter_relative() {
let fragment = "Test";
let result = Builder::new()
.attribute_filter(|elem, attr, value| {
assert_eq!("img", elem);
match (attr, value) {
("src", "imgtest") => Some("rewrite".into()),
("alt", "test") => Some("altalt".into()),
_ => panic!("unexpected"),
}
})
.url_relative(UrlRelative::RewriteWithBase(
Url::parse("https://example.com/base/#").unwrap(),
))
.clean(fragment)
.to_string();
assert_eq!(
result,
r#"Test"#
);
}
#[test]
fn rewrite_url_relative_no_rel() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::RewriteWithBase(
Url::parse("http://example.com/").unwrap(),
))
.link_rel(None)
.clean(fragment)
.to_string();
assert_eq!(result, "Test");
}
#[test]
fn deny_url_relative() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::Deny)
.clean(fragment)
.to_string();
assert_eq!(result, "Test");
}
#[test]
fn replace_rel() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::PassThrough)
.clean(fragment)
.to_string();
assert_eq!(
result,
"Test"
);
}
#[test]
fn consider_rel_still_banned() {
let fragment = "Test";
let result = Builder::new()
.url_relative(UrlRelative::PassThrough)
.link_rel(None)
.clean(fragment)
.to_string();
assert_eq!(result, "Test");
}
#[test]
fn object_data() {
let fragment = "Test\
M";
let expected = r#"TestM"#;
let result = Builder::new()
.tags(hashset!["span", "object"])
.generic_attributes(hashset!["data"])
.clean(fragment)
.to_string();
assert_eq!(result, expected);
}
#[test]
fn remove_attributes() {
let fragment = "";
let result = Builder::new().clean(fragment);
assert_eq!(
result.to_string(),
""
);
}
#[test]
fn quotes_in_attrs() {
let fragment = "contents";
let result = clean(fragment);
assert_eq!(result, "contents");
}
#[test]
#[should_panic]
fn panic_if_rel_is_allowed_and_replaced_generic() {
Builder::new()
.link_rel(Some("noopener noreferrer"))
.generic_attributes(hashset!["rel"])
.clean("something");
}
#[test]
#[should_panic]
fn panic_if_rel_is_allowed_and_replaced_a() {
Builder::new()
.link_rel(Some("noopener noreferrer"))
.tag_attributes(hashmap![
"a" => hashset!["rel"],
])
.clean("something");
}
#[test]
fn no_panic_if_rel_is_allowed_and_replaced_span() {
Builder::new()
.link_rel(Some("noopener noreferrer"))
.tag_attributes(hashmap![
"span" => hashset!["rel"],
])
.clean("s");
}
#[test]
fn no_panic_if_rel_is_allowed_and_not_replaced_generic() {
Builder::new()
.link_rel(None)
.generic_attributes(hashset!["rel"])
.clean("s");
}
#[test]
fn no_panic_if_rel_is_allowed_and_not_replaced_a() {
Builder::new()
.link_rel(None)
.tag_attributes(hashmap![
"a" => hashset!["rel"],
])
.clean("s");
}
#[test]
fn dont_close_void_elements() {
let fragment = "
";
let result = clean(fragment);
assert_eq!(result.to_string(), "
");
}
#[should_panic]
#[test]
fn panic_on_allowed_classes_tag_attributes() {
let fragment = "Hey
";
Builder::new()
.link_rel(None)
.tag_attributes(hashmap![
"p" => hashset!["class"],
"a" => hashset!["class"],
])
.allowed_classes(hashmap![
"p" => hashset!["foo", "bar"],
"a" => hashset!["baz"],
])
.clean(fragment);
}
#[should_panic]
#[test]
fn panic_on_allowed_classes_generic_attributes() {
let fragment = "Hey
";
Builder::new()
.link_rel(None)
.generic_attributes(hashset!["class", "href", "some-foo"])
.allowed_classes(hashmap![
"p" => hashset!["foo", "bar"],
"a" => hashset!["baz"],
])
.clean(fragment);
}
#[test]
fn remove_non_allowed_classes() {
let fragment = "Hey
";
let result = Builder::new()
.link_rel(None)
.allowed_classes(hashmap![
"p" => hashset!["foo", "bar"],
"a" => hashset!["baz"],
])
.clean(fragment);
assert_eq!(
result.to_string(),
"Hey
"
);
}
#[test]
fn remove_non_allowed_classes_with_tag_class() {
let fragment = "Hey
";
let result = Builder::new()
.link_rel(None)
.tag_attributes(hashmap![
"div" => hashset!["class"],
])
.allowed_classes(hashmap![
"p" => hashset!["foo", "bar"],
"a" => hashset!["baz"],
])
.clean(fragment);
assert_eq!(
result.to_string(),
"Hey
"
);
}
#[test]
fn allowed_classes_ascii_whitespace() {
// According to https://infra.spec.whatwg.org/#ascii-whitespace,
// TAB (\t), LF (\n), FF (\x0C), CR (\x0D) and SPACE (\x20) are
// considered to be ASCII whitespace. Unicode whitespace characters
// and VT (\x0B) aren't ASCII whitespace.
let fragment = "";
let result = Builder::new()
.allowed_classes(hashmap![
"p" => hashset!["a", "b", "c", "d", "e", "f", "g"],
])
.clean(fragment);
assert_eq!(result.to_string(), r#"
"#);
}
#[test]
fn remove_non_allowed_attributes_with_tag_attribute_values() {
let fragment = "";
let result = Builder::new()
.tag_attribute_values(hashmap![
"p" => hashmap![
"data-label" => hashset!["bar"],
],
])
.tag_attributes(hashmap![
"p" => hashset!["name"],
])
.clean(fragment);
assert_eq!(result.to_string(), "",);
}
#[test]
fn keep_allowed_attributes_with_tag_attribute_values() {
let fragment = "";
let result = Builder::new()
.tag_attribute_values(hashmap![
"p" => hashmap![
"data-label" => hashset!["bar"],
],
])
.tag_attributes(hashmap![
"p" => hashset!["name"],
])
.clean(fragment);
assert_eq!(
result.to_string(),
"",
);
}
#[test]
fn tag_attribute_values_case_insensitive() {
let fragment = "";
let result = Builder::new()
.tags(hashset!["input"])
.tag_attribute_values(hashmap![
"input" => hashmap![
"type" => hashset!["checkbox"],
],
])
.tag_attributes(hashmap![
"input" => hashset!["name"],
])
.clean(fragment);
assert_eq!(result.to_string(), "",);
}
#[test]
fn set_tag_attribute_values() {
let fragment = "Link";
let result = Builder::new()
.link_rel(None)
.add_tag_attributes("a", &["target"])
.set_tag_attribute_value("a", "target", "_blank")
.clean(fragment);
assert_eq!(
result.to_string(),
"Link",
);
}
#[test]
fn update_existing_set_tag_attribute_values() {
let fragment = "Link";
let result = Builder::new()
.link_rel(None)
.add_tag_attributes("a", &["target"])
.set_tag_attribute_value("a", "target", "_blank")
.clean(fragment);
assert_eq!(
result.to_string(),
"Link",
);
}
#[test]
fn unwhitelisted_set_tag_attribute_values() {
let fragment = "hi";
let result = Builder::new()
.set_tag_attribute_value("my-elem", "my-attr", "val")
.clean(fragment);
assert_eq!(result.to_string(), "hi",);
}
#[test]
fn remove_entity_link() {
let fragment = "Click me!";
let result = clean(fragment);
assert_eq!(
result.to_string(),
"Click me!"
);
}
#[test]
fn remove_relative_url_evaluate() {
fn is_absolute_path(url: &str) -> bool {
let u = url.as_bytes();
// `//a/b/c` is "protocol-relative", meaning "a" is a hostname
// `/a/b/c` is an absolute path, and what we want to do stuff to.
u.get(0) == Some(&b'/') && u.get(1) != Some(&b'/')
}
fn is_banned(url: &str) -> bool {
let u = url.as_bytes();
u.get(0) == Some(&b'b') && u.get(1) == Some(&b'a')
}
fn evaluate(url: &str) -> Option> {
if is_absolute_path(url) {
Some(Cow::Owned(String::from("/root") + url))
} else if is_banned(url) {
None
} else {
Some(Cow::Borrowed(url))
}
}
let a = Builder::new()
.url_relative(UrlRelative::Custom(Box::new(evaluate)))
.clean("bannedfixedpassedskipped")
.to_string();
assert_eq!(a, "bannedfixedpassedskipped");
}
#[test]
fn remove_relative_url_evaluate_b() {
fn is_absolute_path(url: &str) -> bool {
let u = url.as_bytes();
// `//a/b/c` is "protocol-relative", meaning "a" is a hostname
// `/a/b/c` is an absolute path, and what we want to do stuff to.
u.get(0) == Some(&b'/') && u.get(1) != Some(&b'/')
}
fn is_banned(url: &str) -> bool {
let u = url.as_bytes();
u.get(0) == Some(&b'b') && u.get(1) == Some(&b'a')
}
fn evaluate(url: &str) -> Option> {
if is_absolute_path(url) {
Some(Cow::Owned(String::from("/root") + url))
} else if is_banned(url) {
None
} else {
Some(Cow::Borrowed(url))
}
}
let a = Builder::new()
.url_relative(UrlRelative::Custom(Box::new(evaluate)))
.clean("bannedbannedbanned")
.to_string();
assert_eq!(a, "bannedbannedbanned");
}
#[test]
fn remove_relative_url_evaluate_c() {
// Don't run on absolute URLs.
fn evaluate(_: &str) -> Option> {
return Some(Cow::Owned(String::from("invalid")));
}
let a = Builder::new()
.url_relative(UrlRelative::Custom(Box::new(evaluate)))
.clean("google")
.to_string();
assert_eq!(
a,
"google"
);
}
#[test]
fn clean_children_of_bad_element() {
let fragment = "ab";
let result = Builder::new().clean(fragment);
assert_eq!(result.to_string(), "ab");
}
#[test]
fn reader_input() {
let fragment = b"an example";
let result = Builder::new().clean_from_reader(&fragment[..]);
assert!(result.is_ok());
assert_eq!(result.unwrap().to_string(), "an example");
}
#[test]
fn reader_non_utf8() {
let fragment = b"non-utf8 \xF0\x90\x80string";
let result = Builder::new().clean_from_reader(&fragment[..]);
assert!(result.is_ok());
assert_eq!(result.unwrap().to_string(), "non-utf8 \u{fffd}string");
}
#[test]
fn display_impl() {
let fragment = r#"a link"#;
let result = Builder::new().link_rel(None).clean(fragment);
assert_eq!(format!("{}", result), "a link");
}
#[test]
fn debug_impl() {
let fragment = r#"a link"#;
let result = Builder::new().link_rel(None).clean(fragment);
assert_eq!(format!("{:?}", result), "Document(a link)");
}
#[cfg(ammonia_unstable)]
#[test]
fn to_dom_node() {
let fragment = r#"a link"#;
let result = Builder::new().link_rel(None).clean(fragment);
let _node = result.to_dom_node();
}
#[test]
fn string_from_document() {
let fragment = r#"a link"#;
let result = String::from(Builder::new().link_rel(None).clean(fragment));
assert_eq!(format!("{}", result), "a link");
}
fn require_sync(_: T) {}
fn require_send(_: T) {}
#[test]
fn require_sync_and_send() {
require_sync(Builder::new());
require_send(Builder::new());
}
#[test]
fn id_prefixed() {
let fragment = "