//! Tests for the parity harness. //! //! The harness is what every phase-3 conversion trusts, so it is tested on both //! sides: that it ignores what it claims to ignore, and that it still fails on //! everything else. A parity harness that quietly passes is worse than none, //! because the conversion's whole safety argument is that this file said yes. // Just the one module, not `mod harness;`. These are unit tests for the // normalizer and the switch: neither serves a request, so pulling the database, // storage and Stripe harnesses in would cost a much slower build for nothing. // The conversions' own parity tests go through the full harness. #[path = "harness/parity.rs"] mod parity; use parity::Parity; // --- what it forgives ------------------------------------------------------- #[test] fn attribute_order_is_not_a_difference() { Parity::strict().assert( "t", r#"
"#, r#""#, ); } #[test] fn class_order_is_not_a_difference() { // A description emits classes in whatever order it composes them; a // template emits them in the order somebody typed. Parity::strict().assert( "t", r#""#, r#""#, ); } #[test] fn whitespace_between_tags_collapses() { Parity::strict().assert( "t", "one two\n\tthree
", "one two three
"); } #[test] fn comments_are_not_a_difference() { Parity::strict().assert( "t", "Saved.
", "Saved
"); } #[test] #[should_panic(expected = "does not render the same page")] fn different_nesting_fails() { // The case dropping end tags would have missed: same tags, same text, and // the region closes in the wrong place. Parity::strict().assert( "t", "x
x
one two", "
one two"); } #[test] #[should_panic(expected = "does not render the same page")] fn a_missing_doctype_fails() { // Not pedantry: it is the difference between standards and quirks mode. Parity::strict().assert("t", "", ""); } // --- the allowlist ---------------------------------------------------------- #[test] fn a_named_attribute_can_be_forgiven() { // Retiring the private data-action vocabulary is progress, and it is named // per screen rather than ignored everywhere. Parity::strict().ignoring_attr("data-action").assert( "t", r#""#, r#""#, ); } #[test] #[should_panic(expected = "does not render the same page")] fn forgiving_one_attribute_does_not_forgive_its_neighbours() { Parity::strict().ignoring_attr("data-action").assert( "t", r#""#, r#""#, ); } #[test] fn a_named_class_can_be_forgiven() { Parity::strict().ignoring_class("raised").assert( "t", r#""#, r#""#, ); } #[test] fn a_class_attribute_emptied_by_the_allowlist_matches_having_none() { Parity::strict().ignoring_class("raised").assert( "t", "", r#""#, ); } // --- the failure message ---------------------------------------------------- #[test] fn the_failure_names_the_screen_and_shows_both_sides() { let err = std::panic::catch_unwind(|| { Parity::strict().assert("item_pricing", "
a
", "b
"); }) .expect_err("it fails"); let msg = err .downcast_ref::