use autumn_plugin_react::Island;
use maud::Render as _;
use proptest::prelude::*;
fn unescape(s: &str) -> String {
s.replace(""", "\"")
.replace("<", "<")
.replace(">", ">")
.replace("&", "&")
}
fn attr<'a>(html: &'a str, name: &str) -> Option<&'a str> {
let start = html.find(&format!(" {name}=\""))? + name.len() + 3;
let len = html[start..].find('"')?;
Some(&html[start..start + len])
}
proptest! {
#[test]
fn props_round_trip(map in proptest::collection::btree_map(".*", ".*", 0..6)) {
let html = Island::new("X").props(&map).unwrap().render().into_string();
let raw = attr(&html, "data-react-props").unwrap();
let back: std::collections::BTreeMap<String, String> =
serde_json::from_str(&unescape(raw)).unwrap();
prop_assert_eq!(back, map);
}
#[test]
fn values_cannot_break_out(name in ".*", id in ".*", class in ".*", value in ".*") {
let html = Island::new(name.clone())
.id(id.clone())
.class(class.clone())
.props(&serde_json::json!({ "v": value }))
.unwrap()
.render()
.into_string();
prop_assert_eq!(html.matches('<').count(), 2, "{}", html);
prop_assert_eq!(unescape(attr(&html, "data-react-island").unwrap()), name);
prop_assert_eq!(unescape(attr(&html, "id").unwrap()), id);
prop_assert_eq!(unescape(attr(&html, "class").unwrap()), class);
}
#[test]
fn extra_attribute_values_cannot_break_out(value in ".*") {
let html = Island::new("X")
.attr("aria-label", value.clone())
.unwrap()
.render()
.into_string();
prop_assert_eq!(html.matches('<').count(), 2, "{}", html);
prop_assert_eq!(unescape(attr(&html, "aria-label").unwrap()), value);
}
}