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(), "\ngreeting

Hello 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()]), "hello
")] #[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")]), "\"bar\"")] #[case(ul([("foo", "bar").into()], [li([("a", "b").into()], ["hello".into()])]), "")] #[case(ol([("foo", "bar").into()], [li([("a", "b").into()], ["hello".into()])]), "
  1. hello
")] #[case(section([("foo", "bar").into()], ["hello".into()]), "
hello
")] #[case(article([("foo", "bar").into()], ["hello".into()]), "
hello
")] #[case(header([("foo", "bar").into()], ["hello".into()]), "
hello
")] #[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()]), "
hello
")] 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, ""); }