1extern crate alloc;
4
5mod attribute_set;
6mod content;
7mod error;
8mod rule;
9mod validation;
10mod variant;
11
12pub use self::error::*;
13use self::{
14 attribute_set::AttributeSet, content::Content, rule::Rule, validation::validate_rule,
15 variant::Variant,
16};
17use muffy_document::document::Element;
18use muffy_validation_macro::html;
19
20html! {}
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25 use alloc::sync::Arc;
26 use muffy_document::document::Node;
27 use regex::Regex;
28
29 fn create_element(
30 name: &str,
31 attributes: Vec<(&str, &str)>,
32 children: Vec<Element>,
33 ) -> Element {
34 Element::new(
35 name.to_owned(),
36 attributes
37 .into_iter()
38 .map(|(k, v)| (k.to_owned(), v.to_owned()))
39 .collect(),
40 children
41 .into_iter()
42 .map(|e| Arc::new(Node::Element(e)))
43 .collect(),
44 )
45 }
46
47 #[test]
48 fn validate_invalid_element_name() {
49 let element = create_element("invalid", vec![], vec![]);
50
51 assert_eq!(
52 validate_html_element(&element, &[], &[]),
53 Err(MarkupError::UnknownTag("invalid".to_owned()))
54 );
55 }
56
57 mod div {
58 use super::*;
59
60 #[test]
61 fn validate_valid_attribute_name_prefix() {
62 let element = create_element("div", vec![("lang", "en"), ("xml:lang", "en")], vec![]);
63
64 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
65 }
66
67 #[test]
68 fn validate_valid_element() {
69 let element = create_element("div", vec![], vec![]);
70
71 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
72 }
73
74 #[test]
75 fn validate_valid_attributes() {
76 let element = create_element("div", vec![("id", "foo"), ("class", "bar")], vec![]);
77
78 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
79 }
80
81 #[test]
82 fn validate_invalid_attribute() {
83 let element = create_element("div", vec![("invalid", "foo")], vec![]);
84
85 assert_eq!(
86 validate_html_element(&element, &[], &[]),
87 Err(MarkupError::InvalidElement {
88 invalid_attributes: [("invalid".into(), [AttributeError::NotAllowed].into())]
89 .into(),
90 invalid_children: Default::default(),
91 missing_attributes: Default::default(),
92 missing_children: Default::default(),
93 })
94 );
95 }
96
97 #[test]
98 fn validate_multiple_invalid_attributes() {
99 let element = create_element(
100 "div",
101 vec![("invalid-one", "foo"), ("invalid-two", "bar")],
102 vec![],
103 );
104
105 assert_eq!(
106 validate_html_element(&element, &[], &[]),
107 Err(MarkupError::InvalidElement {
108 invalid_attributes: [
109 ("invalid-one".into(), [AttributeError::NotAllowed].into()),
110 ("invalid-two".into(), [AttributeError::NotAllowed].into()),
111 ]
112 .into(),
113 invalid_children: Default::default(),
114 missing_attributes: Default::default(),
115 missing_children: Default::default(),
116 })
117 );
118 }
119
120 #[test]
121 fn validate_ignored_attribute_regex() {
122 let element = create_element("div", vec![("data-foo", "bar")], vec![]);
123
124 assert_eq!(
125 validate_html_element(&element, &[Regex::new("^data-.*$").unwrap()], &[]),
126 Ok(())
127 );
128 }
129
130 #[test]
131 fn validate_ignored_element_regex() {
132 let element = create_element(
133 "div",
134 vec![],
135 vec![create_element("custom-element-123", vec![], vec![])],
136 );
137
138 assert_eq!(
139 validate_html_element(&element, &[], &[Regex::new("^custom-element-.*$").unwrap()]),
140 Ok(())
141 );
142 }
143
144 #[test]
145 fn validate_ignored_unknown_tag_regex() {
146 let element = create_element("custom-element-456", vec![], vec![]);
147
148 assert_eq!(
149 validate_html_element(&element, &[], &[Regex::new("^custom-element-.*$").unwrap()]),
150 Ok(())
151 );
152 }
153
154 #[test]
155 fn validate_ignored_known_tag_regex() {
156 let element = create_element("div", vec![("invalid", "foo")], vec![]);
157
158 assert_eq!(
159 validate_html_element(&element, &[], &[Regex::new("^div$").unwrap()]),
160 Ok(())
161 );
162 }
163
164 #[test]
165 fn validate_non_ignored_known_tag_regex() {
166 let element = create_element("div", vec![("invalid", "foo")], vec![]);
167
168 assert_eq!(
169 validate_html_element(&element, &[], &[Regex::new("^span$").unwrap()]),
170 Err(MarkupError::InvalidElement {
171 invalid_attributes: [("invalid".into(), [AttributeError::NotAllowed].into())]
172 .into(),
173 invalid_children: Default::default(),
174 missing_attributes: Default::default(),
175 missing_children: Default::default(),
176 })
177 );
178 }
179
180 #[test]
181 fn validate_valid_child() {
182 let element = create_element("div", vec![], vec![create_element("p", vec![], vec![])]);
183
184 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
185 }
186
187 #[test]
188 fn validate_valid_svg_child() {
189 let element =
190 create_element("div", vec![], vec![create_element("svg", vec![], vec![])]);
191
192 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
193 }
194 }
195
196 mod p {
197 use super::*;
198
199 #[test]
200 fn validate_valid_element() {
201 let element = create_element("p", vec![], vec![]);
202
203 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
204 }
205
206 #[test]
207 fn validate_valid_text() {
208 let element = Element::new(
209 "p".into(),
210 vec![],
211 vec![Arc::new(Node::Text("hello".into()))],
212 );
213
214 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
215 }
216
217 #[test]
218 fn validate_invalid_child() {
219 let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
220
221 assert_eq!(
222 validate_html_element(&element, &[], &[]),
223 Err(MarkupError::InvalidElement {
224 invalid_attributes: Default::default(),
225 invalid_children: [("div".into(), [ChildError::NotAllowed].into())].into(),
226 missing_attributes: Default::default(),
227 missing_children: Default::default(),
228 })
229 );
230 }
231
232 #[test]
233 fn validate_multiple_invalid_children() {
234 let element = create_element(
235 "p",
236 vec![],
237 vec![
238 create_element("div", vec![], vec![]),
239 create_element("table", vec![], vec![]),
240 ],
241 );
242
243 assert_eq!(
244 validate_html_element(&element, &[], &[]),
245 Err(MarkupError::InvalidElement {
246 invalid_attributes: Default::default(),
247 invalid_children: [
248 ("div".into(), [ChildError::NotAllowed].into()),
249 ("table".into(), [ChildError::NotAllowed].into()),
250 ]
251 .into(),
252 missing_attributes: Default::default(),
253 missing_children: Default::default(),
254 })
255 );
256 }
257
258 #[test]
259 fn validate_ignored_known_tag_regex() {
260 let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
261
262 assert_eq!(
263 validate_html_element(&element, &[], &[Regex::new("^p$").unwrap()]),
264 Ok(())
265 );
266 }
267 }
268
269 mod a {
270 use super::*;
271
272 #[test]
273 fn validate_valid_link() {
274 let element = create_element("a", vec![("href", "/")], vec![]);
275
276 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
277 }
278
279 #[test]
280 fn validate_valid_prefixed_link() {
281 let element = create_element("a", vec![("xlink:href", "/")], vec![]);
282
283 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
284 }
285
286 #[test]
287 fn validate_valid_placeholder_link() {
288 let element = create_element("a", vec![], vec![]);
289
290 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
291 }
292
293 #[test]
294 fn validate_missing_href() {
295 let element = create_element("a", vec![("download", "")], vec![]);
296
297 assert_eq!(
298 validate_html_element(&element, &[], &[]),
299 Err(MarkupError::InvalidElement {
300 invalid_attributes: Default::default(),
301 invalid_children: Default::default(),
302 missing_attributes: ["href".into()].into(),
303 missing_children: Default::default(),
304 })
305 );
306 }
307 }
308
309 mod mark {
310 use super::*;
311
312 #[test]
313 fn validate_valid_element() {
314 let element = create_element("mark", vec![], vec![]);
315
316 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
317 }
318
319 #[test]
320 fn validate_valid_child() {
321 let element =
322 create_element("mark", vec![], vec![create_element("span", vec![], vec![])]);
323
324 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
325 }
326
327 #[test]
328 fn validate_invalid_child() {
329 let element =
330 create_element("mark", vec![], vec![create_element("div", vec![], vec![])]);
331
332 assert_eq!(
333 validate_html_element(&element, &[], &[]),
334 Err(MarkupError::InvalidElement {
335 invalid_attributes: Default::default(),
336 invalid_children: [("div".into(), [ChildError::NotAllowed].into())].into(),
337 missing_attributes: Default::default(),
338 missing_children: Default::default(),
339 })
340 );
341 }
342 }
343
344 mod html {
345 use super::*;
346
347 #[test]
348 fn validate_missing_children() {
349 let element = create_element("html", vec![], vec![]);
350
351 assert_eq!(
352 validate_html_element(&element, &[], &[]),
353 Err(MarkupError::InvalidElement {
354 invalid_attributes: Default::default(),
355 invalid_children: Default::default(),
356 missing_attributes: Default::default(),
357 missing_children: ["head".into()].into(),
358 })
359 );
360 }
361
362 #[test]
363 fn validate_valid_children() {
364 let element = create_element(
365 "html",
366 vec![],
367 vec![
368 create_element("head", vec![], vec![]),
369 create_element("body", vec![], vec![]),
370 ],
371 );
372
373 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
374 }
375
376 #[test]
377 fn validate_misplaced_children() {
378 let element = create_element(
379 "html",
380 vec![],
381 vec![
382 create_element("body", vec![], vec![]),
383 create_element("head", vec![], vec![]),
384 ],
385 );
386
387 assert_eq!(
388 validate_html_element(&element, &[], &[]),
389 Err(MarkupError::InvalidElement {
390 invalid_attributes: Default::default(),
391 invalid_children: [("body".into(), [ChildError::Misplaced].into())].into(),
392 missing_attributes: Default::default(),
393 missing_children: Default::default(),
394 })
395 );
396 }
397 }
398
399 mod head {
400 use super::*;
401
402 #[test]
403 fn validate_valid_child() {
404 let element = create_element(
405 "head",
406 vec![],
407 vec![create_element("title", vec![], vec![])],
408 );
409
410 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
411 }
412
413 #[test]
414 fn validate_missing_title() {
415 let element = create_element("head", vec![], vec![]);
416
417 assert_eq!(
418 validate_html_element(&element, &[], &[]),
419 Err(MarkupError::InvalidElement {
420 invalid_attributes: Default::default(),
421 invalid_children: Default::default(),
422 missing_attributes: Default::default(),
423 missing_children: ["title".into()].into(),
424 })
425 );
426 }
427
428 #[test]
429 fn validate_invalid_child() {
430 let element = create_element("head", vec![], vec![create_element("p", vec![], vec![])]);
431
432 assert_eq!(
433 validate_html_element(&element, &[], &[]),
434 Err(MarkupError::InvalidElement {
435 invalid_attributes: Default::default(),
436 invalid_children: [("p".into(), [ChildError::NotAllowed].into())].into(),
437 missing_attributes: Default::default(),
438 missing_children: ["title".into()].into(),
439 })
440 );
441 }
442 }
443
444 mod title {
445 use super::*;
446
447 #[test]
448 fn validate_invalid_child() {
449 let element =
450 create_element("title", vec![], vec![create_element("div", vec![], vec![])]);
451
452 assert_eq!(
453 validate_html_element(&element, &[], &[]),
454 Err(MarkupError::InvalidElement {
455 invalid_attributes: Default::default(),
456 invalid_children: [("div".into(), [ChildError::NotAllowed].into())].into(),
457 missing_attributes: Default::default(),
458 missing_children: Default::default(),
459 })
460 );
461 }
462 }
463
464 mod ul {
465 use super::*;
466
467 #[test]
468 fn validate_valid_child() {
469 let element = create_element("ul", vec![], vec![create_element("li", vec![], vec![])]);
470
471 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
472 }
473
474 #[test]
475 fn validate_whitespace_text() {
476 let element = Element::new(
477 "ul".into(),
478 vec![],
479 vec![
480 Arc::new(Node::Text("\n ".into())),
481 Arc::new(Node::Element(create_element("li", vec![], vec![]))),
482 ],
483 );
484
485 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
486 }
487
488 #[test]
489 fn validate_invalid_text() {
490 let element = Element::new(
491 "ul".into(),
492 vec![],
493 vec![
494 Arc::new(Node::Text("orphan".into())),
495 Arc::new(Node::Element(create_element("li", vec![], vec![]))),
496 ],
497 );
498
499 assert_eq!(
500 validate_html_element(&element, &[], &[]),
501 Err(MarkupError::InvalidElement {
502 invalid_attributes: Default::default(),
503 invalid_children: [("#text".into(), [ChildError::NotAllowed].into())].into(),
504 missing_attributes: Default::default(),
505 missing_children: Default::default(),
506 })
507 );
508 }
509
510 #[test]
511 fn validate_invalid_child() {
512 let element = create_element("ul", vec![], vec![create_element("p", vec![], vec![])]);
513
514 assert_eq!(
515 validate_html_element(&element, &[], &[]),
516 Err(MarkupError::InvalidElement {
517 invalid_attributes: Default::default(),
518 invalid_children: [("p".into(), [ChildError::NotAllowed].into())].into(),
519 missing_attributes: Default::default(),
520 missing_children: Default::default(),
521 })
522 );
523 }
524 }
525
526 mod table {
527 use super::*;
528
529 #[test]
530 fn validate_valid_child() {
531 let element =
532 create_element("table", vec![], vec![create_element("tr", vec![], vec![])]);
533
534 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
535 }
536
537 #[test]
538 fn validate_valid_ordered_children() {
539 let element = create_element(
540 "table",
541 vec![],
542 vec![
543 create_element("caption", vec![], vec![]),
544 create_element("thead", vec![], vec![]),
545 create_element("tbody", vec![], vec![]),
546 create_element("tfoot", vec![], vec![]),
547 ],
548 );
549
550 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
551 }
552
553 #[test]
554 fn validate_misplaced_child() {
555 let element = create_element(
556 "table",
557 vec![],
558 vec![
559 create_element("tfoot", vec![], vec![]),
560 create_element("thead", vec![], vec![]),
561 ],
562 );
563
564 assert_eq!(
565 validate_html_element(&element, &[], &[]),
566 Err(MarkupError::InvalidElement {
567 invalid_attributes: Default::default(),
568 invalid_children: [("thead".into(), [ChildError::Misplaced].into())].into(),
569 missing_attributes: Default::default(),
570 missing_children: Default::default(),
571 })
572 );
573 }
574
575 #[test]
576 fn validate_invalid_child() {
577 let element =
578 create_element("table", vec![], vec![create_element("p", vec![], vec![])]);
579
580 assert_eq!(
581 validate_html_element(&element, &[], &[]),
582 Err(MarkupError::InvalidElement {
583 invalid_attributes: Default::default(),
584 invalid_children: [("p".into(), [ChildError::NotAllowed].into())].into(),
585 missing_attributes: Default::default(),
586 missing_children: Default::default(),
587 })
588 );
589 }
590 }
591
592 mod tr {
593 use super::*;
594
595 #[test]
596 fn validate_valid_children() {
597 let element = create_element(
598 "tr",
599 vec![],
600 vec![
601 create_element("th", vec![], vec![]),
602 create_element("td", vec![], vec![]),
603 ],
604 );
605
606 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
607 }
608 }
609
610 mod form {
611 use super::*;
612
613 #[test]
614 fn validate_valid_attributes() {
615 let element = create_element("form", vec![("action", "/"), ("method", "post")], vec![]);
616
617 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
618 }
619
620 #[test]
621 fn validate_valid_child() {
622 let element = create_element(
623 "form",
624 vec![],
625 vec![create_element("input", vec![], vec![])],
626 );
627
628 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
629 }
630 }
631
632 mod img {
633 use super::*;
634
635 #[test]
636 fn validate_valid_attributes() {
637 let element = create_element(
638 "img",
639 vec![("src", "img.png"), ("alt", "description")],
640 vec![],
641 );
642
643 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
644 }
645 }
646
647 mod picture {
648 use super::*;
649
650 #[test]
651 fn validate_missing_child() {
652 let element = create_element("picture", vec![], vec![]);
653
654 assert_eq!(
655 validate_html_element(&element, &[], &[]),
656 Err(MarkupError::InvalidElement {
657 invalid_attributes: Default::default(),
658 invalid_children: Default::default(),
659 missing_attributes: Default::default(),
660 missing_children: ["img".into()].into(),
661 })
662 );
663 }
664
665 #[test]
666 fn validate_valid_children() {
667 let element = create_element(
668 "picture",
669 vec![],
670 vec![
671 create_element("source", vec![], vec![]),
672 create_element("img", vec![], vec![]),
673 ],
674 );
675
676 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
677 }
678
679 #[test]
680 fn validate_misplaced_child() {
681 let element = create_element(
682 "picture",
683 vec![],
684 vec![
685 create_element("img", vec![], vec![]),
686 create_element("source", vec![], vec![]),
687 ],
688 );
689
690 assert_eq!(
691 validate_html_element(&element, &[], &[]),
692 Err(MarkupError::InvalidElement {
693 invalid_attributes: Default::default(),
694 invalid_children: [("source".into(), [ChildError::Misplaced].into())].into(),
695 missing_attributes: Default::default(),
696 missing_children: Default::default(),
697 })
698 );
699 }
700
701 #[test]
702 fn validate_invalid_child() {
703 let element =
704 create_element("picture", vec![], vec![create_element("p", vec![], vec![])]);
705
706 assert_eq!(
707 validate_html_element(&element, &[], &[]),
708 Err(MarkupError::InvalidElement {
709 invalid_attributes: Default::default(),
710 invalid_children: [("p".into(), [ChildError::NotAllowed].into())].into(),
711 missing_attributes: Default::default(),
712 missing_children: ["img".into()].into(),
713 })
714 );
715 }
716 }
717
718 mod video {
719 use super::*;
720
721 #[test]
722 fn validate_valid_attributes() {
723 let element =
724 create_element("video", vec![("src", "vid.mp4"), ("controls", "")], vec![]);
725
726 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
727 }
728
729 #[test]
730 fn validate_valid_child() {
731 let element = create_element(
732 "video",
733 vec![],
734 vec![create_element("track", vec![], vec![])],
735 );
736
737 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
738 }
739 }
740
741 mod meta {
742 use super::*;
743
744 #[test]
745 fn validate_valid_name_content() {
746 let element = create_element(
747 "meta",
748 vec![("name", "description"), ("content", "stuff")],
749 vec![],
750 );
751
752 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
753 }
754
755 #[test]
756 fn validate_valid_charset() {
757 let element = create_element("meta", vec![("charset", "utf-8")], vec![]);
758
759 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
760 }
761
762 #[test]
763 fn validate_valid_property() {
764 let element = create_element(
765 "meta",
766 vec![("property", "og:image"), ("content", "image.png")],
767 vec![],
768 );
769
770 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
771 }
772
773 #[test]
774 fn validate_missing_content() {
775 let element = create_element("meta", vec![("name", "description")], vec![]);
776
777 assert_eq!(
778 validate_html_element(&element, &[], &[]),
779 Err(MarkupError::InvalidElement {
780 invalid_attributes: Default::default(),
781 invalid_children: Default::default(),
782 missing_attributes: ["content".into()].into(),
783 missing_children: Default::default(),
784 })
785 );
786 }
787
788 #[test]
789 fn validate_conflicting_charset() {
790 let element = create_element(
791 "meta",
792 vec![
793 ("charset", "utf-8"),
794 ("name", "description"),
795 ("content", "stuff"),
796 ],
797 vec![],
798 );
799
800 assert_eq!(
801 validate_html_element(&element, &[], &[]),
802 Err(MarkupError::InvalidElement {
803 invalid_attributes: [("charset".into(), [AttributeError::Conflict].into())]
804 .into(),
805 invalid_children: Default::default(),
806 missing_attributes: Default::default(),
807 missing_children: Default::default(),
808 })
809 );
810 }
811 }
812
813 mod link {
814 use super::*;
815
816 #[test]
817 fn validate_valid_attributes() {
818 let element = create_element(
819 "link",
820 vec![("rel", "stylesheet"), ("href", "style.css")],
821 vec![],
822 );
823
824 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
825 }
826
827 #[test]
828 fn validate_valid_rel_without_href() {
829 let element = create_element("link", vec![("rel", "preload")], vec![]);
830
831 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
832 }
833
834 #[test]
835 fn validate_missing_rel() {
836 let element = create_element("link", vec![("href", "style.css")], vec![]);
837
838 assert_eq!(
841 validate_html_element(&element, &[], &[]),
842 Err(MarkupError::InvalidElement {
843 invalid_attributes: Default::default(),
844 invalid_children: Default::default(),
845 missing_attributes: ["itemprop".into()].into(),
846 missing_children: Default::default(),
847 })
848 );
849 }
850 }
851
852 mod svg {
853 use super::*;
854
855 #[test]
856 fn validate_valid_element() {
857 let element = create_element("svg", vec![], vec![]);
858
859 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
860 }
861
862 #[test]
863 fn validate_valid_attributes() {
864 let element = create_element(
865 "svg",
866 vec![
867 ("version", "1.1"),
868 ("viewBox", "0 0 10 10"),
869 ("width", "10"),
870 ("height", "10"),
871 ],
872 vec![],
873 );
874
875 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
876 }
877
878 #[test]
879 fn validate_valid_aria_attributes() {
880 let element = create_element(
881 "svg",
882 vec![("role", "img"), ("aria-label", "description")],
883 vec![],
884 );
885
886 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
887 }
888
889 #[test]
890 fn validate_valid_child() {
891 let element = create_element(
892 "svg",
893 vec![],
894 vec![create_element("circle", vec![("r", "1")], vec![])],
895 );
896
897 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
898 }
899
900 #[test]
901 fn validate_valid_text_child() {
902 let element = Element::new(
903 "text".into(),
904 vec![],
905 vec![Arc::new(Node::Text("hello".into()))],
906 );
907
908 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
909 }
910
911 #[test]
912 fn validate_valid_camel_case_element() {
913 let element = create_element(
914 "linearGradient",
915 vec![("id", "gradient")],
916 vec![create_element("stop", vec![("offset", "0")], vec![])],
917 );
918
919 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
920 }
921
922 #[test]
923 fn validate_valid_link() {
924 let element = create_element(
925 "a",
926 vec![("href", "/")],
927 vec![create_element("rect", vec![], vec![])],
928 );
929
930 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
931 }
932
933 #[test]
934 fn validate_valid_image_link() {
935 let element = create_element("image", vec![("href", "/foo.png")], vec![]);
936
937 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
938 }
939
940 #[test]
941 fn validate_valid_prefixed_image_link() {
942 let element = create_element("image", vec![("xlink:href", "/foo.png")], vec![]);
943
944 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
945 }
946
947 #[test]
948 fn validate_valid_foreign_object() {
949 let element = create_element(
950 "foreignObject",
951 vec![],
952 vec![create_element("div", vec![], vec![])],
953 );
954
955 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
956 }
957
958 #[test]
959 fn validate_invalid_foreign_object_child() {
960 let element = create_element(
961 "foreignObject",
962 vec![],
963 vec![create_element("title", vec![], vec![])],
964 );
965
966 assert_eq!(
967 validate_html_element(&element, &[], &[]),
968 Err(MarkupError::InvalidElement {
969 invalid_attributes: Default::default(),
970 invalid_children: [("title".into(), [ChildError::NotAllowed].into())].into(),
971 missing_attributes: Default::default(),
972 missing_children: Default::default(),
973 })
974 );
975 }
976
977 #[test]
978 fn validate_invalid_element_name() {
979 let element = create_element("invalid", vec![], vec![]);
980
981 assert_eq!(
982 validate_html_element(&element, &[], &[]),
983 Err(MarkupError::UnknownTag("invalid".to_owned()))
984 );
985 }
986
987 #[test]
988 fn validate_invalid_attribute() {
989 let element = create_element("circle", vec![("invalid", "foo")], vec![]);
990
991 assert_eq!(
992 validate_html_element(&element, &[], &[]),
993 Err(MarkupError::InvalidElement {
994 invalid_attributes: [("invalid".into(), [AttributeError::NotAllowed].into())]
995 .into(),
996 invalid_children: Default::default(),
997 missing_attributes: Default::default(),
998 missing_children: Default::default(),
999 })
1000 );
1001 }
1002
1003 #[test]
1004 fn validate_invalid_child() {
1005 let element =
1006 create_element("svg", vec![], vec![create_element("html", vec![], vec![])]);
1007
1008 assert_eq!(
1009 validate_html_element(&element, &[], &[]),
1010 Err(MarkupError::InvalidElement {
1011 invalid_attributes: Default::default(),
1012 invalid_children: [("html".into(), [ChildError::NotAllowed].into())].into(),
1013 missing_attributes: Default::default(),
1014 missing_children: Default::default(),
1015 })
1016 );
1017 }
1018
1019 #[test]
1020 fn validate_missing_attribute() {
1021 let element = create_element("animate", vec![], vec![]);
1022
1023 assert_eq!(
1024 validate_html_element(&element, &[], &[]),
1025 Err(MarkupError::InvalidElement {
1026 invalid_attributes: Default::default(),
1027 invalid_children: Default::default(),
1028 missing_attributes: ["attributeName".into()].into(),
1029 missing_children: Default::default(),
1030 })
1031 );
1032 }
1033
1034 #[test]
1035 fn validate_ignored_attribute_regex() {
1036 let element = create_element("circle", vec![("data-foo", "bar")], vec![]);
1037
1038 assert_eq!(
1039 validate_html_element(&element, &[Regex::new("^data-.*$").unwrap()], &[]),
1040 Ok(())
1041 );
1042 }
1043
1044 #[test]
1045 fn validate_ignored_element_regex() {
1046 let element = create_element("foreignObject", vec![], vec![]);
1047
1048 assert_eq!(
1049 validate_html_element(&element, &[], &[Regex::new("^foreignObject$").unwrap()]),
1050 Ok(())
1051 );
1052 }
1053 }
1054
1055 mod noscript {
1056 use super::*;
1057
1058 #[test]
1059 fn validate_valid_element() {
1060 let element = create_element("noscript", vec![], vec![]);
1061
1062 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
1063 }
1064
1065 #[test]
1066 fn validate_valid_flow_child() {
1067 let element = create_element(
1068 "noscript",
1069 vec![],
1070 vec![create_element("div", vec![], vec![])],
1071 );
1072
1073 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
1074 }
1075
1076 #[test]
1077 fn validate_valid_head_child() {
1078 let element = create_element(
1079 "noscript",
1080 vec![],
1081 vec![create_element("link", vec![], vec![])],
1082 );
1083
1084 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
1085 }
1086
1087 #[test]
1088 fn validate_invalid_child() {
1089 let element = create_element(
1090 "noscript",
1091 vec![],
1092 vec![create_element("title", vec![], vec![])],
1093 );
1094
1095 assert_eq!(
1096 validate_html_element(&element, &[], &[]),
1097 Err(MarkupError::InvalidElement {
1098 invalid_attributes: Default::default(),
1099 invalid_children: [("title".into(), [ChildError::NotAllowed].into())].into(),
1100 missing_attributes: Default::default(),
1101 missing_children: Default::default(),
1102 })
1103 );
1104 }
1105 }
1106}