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