use rstest::rstest;
use fun_html::{attr::*, elt::*, html, Attribute, Document, Element};
#[test]
fn should_render_empty_document() {
let doc = Document::default();
let string = format!("{doc}");
assert_eq!(
string,
"\n
"
)
}
#[test]
fn should_render_html_document() {
let doc = html(
[lang("en")],
[
head([], [title([], "greeting")]),
body([], [h1([], [text("Hello world!")])]),
],
);
assert_eq!(doc.to_string(), "\ngreetingHello world!
");
}
#[rstest]
#[case(("foo", "bar").into(), "foo=\"bar\"")]
#[case(("x-on:keyup.enter", "doSomething").into(), "x-on:keyup.enter=\"doSomething\"")]
#[case(("@keyup.enter", "doSomething").into(), "@keyup.enter=\"doSomething\"")]
#[case(Attribute::new_unsafe_name("hello".to_string(), "world".to_string()), "hello=\"world\"")]
#[case(id("foo"), "id=\"foo\"")]
#[case(class(["foo"]), "class=\"foo\"")]
#[case(class(["foo", "bar"]), "class=\"foo bar\"")]
#[case(href("foo"), "href=\"foo\"")]
#[case(rel("foo"), "rel=\"foo\"")]
#[case(src("foo"), "src=\"foo\"")]
#[case(type_("foo"), "type=\"foo\"")]
#[case(type_text(), "type=\"text\"")]
#[case(type_password(), "type=\"password\"")]
#[case(type_number(), "type=\"number\"")]
#[case(type_tel(), "type=\"tel\"")]
#[case(type_file(), "type=\"file\"")]
#[case(type_checkbox(), "type=\"checkbox\"")]
#[case(type_radio(), "type=\"radio\"")]
#[case(type_range(), "type=\"range\"")]
#[case(type_email(), "type=\"email\"")]
#[case(type_date(), "type=\"date\"")]
#[case(type_month(), "type=\"month\"")]
#[case(type_hidden(), "type=\"hidden\"")]
#[case(type_reset(), "type=\"reset\"")]
#[case(type_submit(), "type=\"submit\"")]
#[case(integrity("foo"), "integrity=\"foo\"")]
#[case(defer(), "defer")]
#[case(async_(), "async")]
#[case(crossorigin_anonymous(), "crossorigin=\"anonymous\"")]
#[case(crossorigin_use_credentials(), "crossorigin=\"use-credentials\"")]
#[case(download(), "download")]
#[case(download_with_name("myfile.txt"), "download=\"myfile.txt\"")]
#[case(target(AnchorTarget::Blank), "target=\"_blank\"")]
#[case(target_blank(), "target=\"_blank\"")]
#[case(target(AnchorTarget::Self_), "target=\"_self\"")]
#[case(target(AnchorTarget::Top), "target=\"_top\"")]
#[case(target(AnchorTarget::Parent), "target=\"_parent\"")]
#[case(target(AnchorTarget::Frame("myframe".into())), "target=\"myframe\"")]
#[case(charset("foobar"), "charset=\"foobar\"")]
#[case(charset_utf_8(), "charset=\"UTF-8\"")]
#[case(name("hello"), "name=\"hello\"")]
#[case(content("bla"), "content=\"bla\"")]
#[case(alt("bla"), "alt=\"bla\"")]
#[case(width("10"), "width=\"10\"")]
#[case(height("10"), "height=\"10\"")]
#[case(width_int(10), "width=\"10\"")]
#[case(height_int(10), "height=\"10\"")]
#[case(action("something"), "action=\"something\"")]
#[case(method_get(), "method=\"get\"")]
#[case(method_post(), "method=\"post\"")]
#[case(for_("foo"), "for=\"foo\"")]
#[case(value("hello"), "value=\"hello\"")]
#[case(required(), "required")]
#[case(pattern("foobar"), "pattern=\"foobar\"")]
#[case(min("value"), "min=\"value\"")]
#[case(max("value"), "max=\"value\"")]
#[case(minlength("value"), "minlength=\"value\"")]
#[case(maxlength("value"), "maxlength=\"value\"")]
#[case(multiple(), "multiple")]
#[case(placeholder("hello"), "placeholder=\"hello\"")]
#[case(rows(10), "rows=\"10\"")]
#[case(cols(10), "cols=\"10\"")]
fn should_render_attribute(#[case] attr: Attribute, #[case] expected: &str) {
assert_eq!(attr.to_string(), expected);
}
#[rstest]
#[case(none(), "")]
#[case([div([], []), div([], [])].into(), "")]
#[case(div([], div([], [])), "")]
#[case(text("hello"), "hello")]
#[case(text("hello".to_string()), "hello")]
#[case("hello".into(), "hello")]
#[case("hello".to_string().into(), "hello")]
#[case([div([], ["a".into()]), div([], ["b".into()])].into(), "a
b
")]
#[case(raw(""), "")]
#[case(raw_unsafe("".to_string()), "")]
#[case(link([("foo", "bar").into()]), "")]
#[case(
link_stylesheet("/styles.css"),
""
)]
#[case(script([("foo", "bar").into()], "alert('hello');"), "")]
#[case(script_empty([src("/foo.js")]), "")]
#[case(meta([("foo", "bar").into()]), "")]
#[case(meta_charset_utf_8(), "")]
#[case(
meta_viewport(),
""
)]
#[case(
meta_color_scheme("dark"),
""
)]
#[case(div([("foo", "bar").into()], ["hello".into()]), "hello
")]
#[case(div([("foo", "bar".to_string()).into()], [text("hello".to_string())]), "hello
")]
#[case(head([id("foo")], [text("hello")]), "hello")]
#[case(title([("foo", "bar").into()], "hello"), "hello")]
#[case(body([id("foo")], [text("hello")]), "hello")]
#[case(h1([id("foo")], [text("hello")]), "hello
")]
#[case(h2([id("foo")], [text("hello")]), "hello
")]
#[case(h3([id("foo")], [text("hello")]), "hello
")]
#[case(h4([id("foo")], [text("hello")]), "hello
")]
#[case(h5([id("foo")], [text("hello")]), "hello
")]
#[case(h6([id("foo")], [text("hello")]), "hello
")]
#[case(p([("foo", "bar").into()], ["hello".into()]), "hello
")]
#[case(br([("foo", "bar").into()]), "
")]
#[case(small([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(span([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(table([("foo", "bar").into()], ["hello".into()]), "")]
#[case(tr([("foo", "bar").into()], ["hello".into()]), "hello
")]
#[case(td([("foo", "bar").into()], ["hello".into()]), "hello | ")]
#[case(th([("foo", "bar").into()], ["hello".into()]), "hello | ")]
#[case(thead([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(tbody([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(tfoot([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(a([href("/somepath")], ["visit this cool link!".into()]), "visit this cool link!")]
#[case(img([src("foo"), alt("bar")]), "")]
#[case(ul([("foo", "bar").into()], [li([("a", "b").into()], ["hello".into()])]), "")]
#[case(ol([("foo", "bar").into()], [li([("a", "b").into()], ["hello".into()])]), "- hello
")]
#[case(section([("foo", "bar").into()], ["hello".into()]), "")]
#[case(article([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(header([("foo", "bar").into()], ["hello".into()]), "")]
#[case(main([("foo", "bar").into()], ["hello".into()]), "hello")]
#[case(footer([("foo", "bar").into()], ["hello".into()]), "")]
#[case(
form([action("/do_something"), method_get()], [input([name("foo")])]),
r#""#
)]
#[case(
select([name("foo")], [option([value("bar")], ["coucou".into()])]),
r#""#
)]
#[case(input([name("foo"), type_text()]), "")]
#[case(textarea([name("foo")], "hello world"), "")]
#[case(button([("foo", "bar").into()], ["hello".into()]), "")]
#[case(label([for_("foo")], ["hello".into()]), "")]
#[case(fieldset([("foo", "bar").into()], ["hello".into()]), "")]
fn should_render_element(#[case] def: Element, #[case] expected: &str) {
assert_eq!(def.to_string(), expected);
}
#[test]
fn text_should_be_escaped() {
let input = "";
let string = text(input).to_string();
assert_eq!(string, "<script>alert('hello');</script>");
}
#[rstest]
fn attribute_should_be_escaped() {
let string = div(
[("foo", "');").to_string();
assert_eq!(string, "");
}