use wafrift_encoding::contextual::validate_in_context;
use wafrift_types::injection_context::InjectionContext;
#[test]
fn xml_cdata_rejects_terminator_sequence() {
let err = validate_in_context("safe ]]> evil", InjectionContext::XmlCdata)
.expect_err("must reject CDATA terminator");
assert!(format!("{err}").contains("]]>"));
}
#[test]
fn xml_cdata_accepts_clean_payload() {
validate_in_context("clean cdata content", InjectionContext::XmlCdata)
.expect("clean payload must pass");
}
#[test]
fn xml_text_rejects_raw_lt() {
let err = validate_in_context("a < b", InjectionContext::XmlText)
.expect_err("must reject unescaped <");
assert!(format!("{err}").contains('<'));
}
#[test]
fn xml_text_rejects_unescaped_ampersand() {
let _err = validate_in_context("rock & roll", InjectionContext::XmlText)
.expect_err("must reject unescaped &");
}
#[test]
fn xml_text_accepts_proper_entity_references() {
validate_in_context("& and <", InjectionContext::XmlText)
.expect("named entities must pass");
validate_in_context("A and A", InjectionContext::XmlText)
.expect("numeric and hex entities must pass");
}
#[test]
fn html_attribute_rejects_raw_lt() {
let err = validate_in_context("a < b", InjectionContext::HtmlAttribute)
.expect_err("must reject <");
assert!(format!("{err}").contains('<'));
}
#[test]
fn html_attribute_rejects_double_quote() {
let err = validate_in_context("hello \"world\"", InjectionContext::HtmlAttribute)
.expect_err("must reject double-quote attr breakout");
assert!(format!("{err}").contains('"'));
}
#[test]
fn html_attribute_rejects_single_quote() {
let err = validate_in_context("don't", InjectionContext::HtmlAttribute)
.expect_err("must reject single-quote attr breakout");
assert!(format!("{err}").contains('\''));
}
#[test]
fn html_attribute_rejects_unescaped_ampersand() {
let _err = validate_in_context("a & b", InjectionContext::HtmlAttribute)
.expect_err("must reject unescaped &");
}
#[test]
fn html_attribute_accepts_clean_value() {
validate_in_context("clean value", InjectionContext::HtmlAttribute)
.expect("clean payload must pass");
validate_in_context("with & entity", InjectionContext::HtmlAttribute)
.expect("entity references must pass");
}
#[test]
fn html_text_rejects_raw_lt() {
let err = validate_in_context("<script>", InjectionContext::HtmlText)
.expect_err("must reject < (would start tag)");
assert!(format!("{err}").contains('<'));
}
#[test]
fn html_text_rejects_unescaped_ampersand() {
let _err = validate_in_context("AT&T", InjectionContext::HtmlText)
.expect_err("must reject unescaped &");
}
#[test]
fn html_text_accepts_clean_text_and_entities() {
validate_in_context("plain text only", InjectionContext::HtmlText)
.expect("clean text must pass");
validate_in_context(
"AT&T and <br> and —",
InjectionContext::HtmlText,
)
.expect("entity-encoded text must pass");
}
#[test]
fn escape_then_validate_round_trip_html_attr() {
use wafrift_encoding::contextual::escape_for_context;
let dangerous = r#"<script>alert("xss")</script> & 'oops'"#;
let escaped =
escape_for_context(dangerous, InjectionContext::HtmlAttribute).expect("escape ok");
validate_in_context(&escaped, InjectionContext::HtmlAttribute)
.expect("escape output must pass validate");
}
#[test]
fn escape_then_validate_round_trip_html_text() {
use wafrift_encoding::contextual::escape_for_context;
let dangerous = "<a>AT&T</a>";
let escaped = escape_for_context(dangerous, InjectionContext::HtmlText).expect("escape ok");
validate_in_context(&escaped, InjectionContext::HtmlText)
.expect("escape output must pass validate");
}
#[test]
fn escape_then_validate_round_trip_xml_text() {
use wafrift_encoding::contextual::escape_for_context;
let dangerous = "<root>a & b</root>";
let escaped = escape_for_context(dangerous, InjectionContext::XmlText).expect("escape ok");
validate_in_context(&escaped, InjectionContext::XmlText)
.expect("escape output must pass validate");
}