1extern crate alloc;
4
5mod error;
6
7pub use self::error::*;
8use muffy_document::html::Element;
9use muffy_validation_macro::html;
10
11html! {}
12
13#[cfg(test)]
14mod tests {
15 use super::*;
16 use alloc::sync::Arc;
17 use muffy_document::html::Node;
18 use regex::Regex;
19
20 fn create_element(
21 name: &str,
22 attributes: Vec<(&str, &str)>,
23 children: Vec<Element>,
24 ) -> Element {
25 Element::new(
26 name.to_owned(),
27 attributes
28 .into_iter()
29 .map(|(k, v)| (k.to_owned(), v.to_owned()))
30 .collect(),
31 children
32 .into_iter()
33 .map(|e| Arc::new(Node::Element(e)))
34 .collect(),
35 )
36 }
37
38 #[test]
39 fn validate_invalid_element_name() {
40 let element = create_element("invalid", vec![], vec![]);
41
42 assert_eq!(
43 validate_html_element(&element, &[], &[]),
44 Err(MarkupError::UnknownTag("invalid".to_owned()))
45 );
46 }
47
48 mod div {
49 use super::*;
50
51 #[test]
52 fn validate_valid_element() {
53 let element = create_element("div", vec![], vec![]);
54
55 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
56 }
57
58 #[test]
59 fn validate_valid_attributes() {
60 let element = create_element("div", vec![("id", "foo"), ("class", "bar")], vec![]);
61
62 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
63 }
64
65 #[test]
66 fn validate_invalid_attribute() {
67 let element = create_element("div", vec![("invalid", "foo")], vec![]);
68
69 assert_eq!(
70 validate_html_element(&element, &[], &[]),
71 Err(MarkupError::InvalidElement {
72 attributes: [("invalid".into(), [AttributeError::NotAllowed].into())].into(),
73 children: Default::default(),
74 })
75 );
76 }
77
78 #[test]
79 fn validate_multiple_invalid_attributes() {
80 let element = create_element(
81 "div",
82 vec![("invalid-one", "foo"), ("invalid-two", "bar")],
83 vec![],
84 );
85
86 assert_eq!(
87 validate_html_element(&element, &[], &[]),
88 Err(MarkupError::InvalidElement {
89 attributes: [
90 ("invalid-one".into(), [AttributeError::NotAllowed].into()),
91 ("invalid-two".into(), [AttributeError::NotAllowed].into()),
92 ]
93 .into(),
94 children: Default::default(),
95 })
96 );
97 }
98
99 #[test]
100 fn validate_ignored_attribute_regex() {
101 let element = create_element("div", vec![("data-foo", "bar")], vec![]);
102
103 assert_eq!(
104 validate_html_element(&element, &[Regex::new("^data-.*$").unwrap()], &[]),
105 Ok(())
106 );
107 }
108
109 #[test]
110 fn validate_ignored_element_regex() {
111 let element = create_element(
112 "div",
113 vec![],
114 vec![create_element("custom-element-123", vec![], vec![])],
115 );
116
117 assert_eq!(
118 validate_html_element(&element, &[], &[Regex::new("^custom-element-.*$").unwrap()]),
119 Ok(())
120 );
121 }
122
123 #[test]
124 fn validate_ignored_unknown_tag_regex() {
125 let element = create_element("custom-element-456", vec![], vec![]);
126
127 assert_eq!(
128 validate_html_element(&element, &[], &[Regex::new("^custom-element-.*$").unwrap()]),
129 Ok(())
130 );
131 }
132
133 #[test]
134 fn validate_ignored_known_tag_regex() {
135 let element = create_element("div", vec![("invalid", "foo")], vec![]);
136
137 assert_eq!(
138 validate_html_element(&element, &[], &[Regex::new("^div$").unwrap()]),
139 Ok(())
140 );
141 }
142
143 #[test]
144 fn validate_non_ignored_known_tag_regex() {
145 let element = create_element("div", vec![("invalid", "foo")], vec![]);
146
147 assert_eq!(
148 validate_html_element(&element, &[], &[Regex::new("^span$").unwrap()]),
149 Err(MarkupError::InvalidElement {
150 attributes: [("invalid".into(), [AttributeError::NotAllowed].into())].into(),
151 children: Default::default(),
152 })
153 );
154 }
155
156 #[test]
157 fn validate_valid_child() {
158 let element = create_element("div", vec![], vec![create_element("p", vec![], vec![])]);
159
160 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
161 }
162 }
163
164 mod p {
165 use super::*;
166
167 #[test]
168 fn validate_valid_element() {
169 let element = create_element("p", vec![], vec![]);
170
171 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
172 }
173
174 #[test]
175 fn validate_invalid_child() {
176 let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
177
178 assert_eq!(
179 validate_html_element(&element, &[], &[]),
180 Err(MarkupError::InvalidElement {
181 attributes: Default::default(),
182 children: [("div".into(), [ChildError::NotAllowed].into())].into(),
183 })
184 );
185 }
186
187 #[test]
188 fn validate_multiple_invalid_children() {
189 let element = create_element(
190 "p",
191 vec![],
192 vec![
193 create_element("div", vec![], vec![]),
194 create_element("table", vec![], vec![]),
195 ],
196 );
197
198 assert_eq!(
199 validate_html_element(&element, &[], &[]),
200 Err(MarkupError::InvalidElement {
201 attributes: Default::default(),
202 children: [
203 ("div".into(), [ChildError::NotAllowed].into()),
204 ("table".into(), [ChildError::NotAllowed].into()),
205 ]
206 .into(),
207 })
208 );
209 }
210
211 #[test]
212 fn validate_ignored_known_tag_regex() {
213 let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
214
215 assert_eq!(
216 validate_html_element(&element, &[], &[Regex::new("^p$").unwrap()]),
217 Ok(())
218 );
219 }
220 }
221
222 mod mark {
223 use super::*;
224
225 #[test]
226 fn validate_valid_element() {
227 let element = create_element("mark", vec![], vec![]);
228
229 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
230 }
231
232 #[test]
233 fn validate_valid_child() {
234 let element =
235 create_element("mark", vec![], vec![create_element("span", vec![], vec![])]);
236
237 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
238 }
239
240 #[test]
241 fn validate_invalid_child() {
242 let element =
243 create_element("mark", vec![], vec![create_element("div", vec![], vec![])]);
244
245 assert_eq!(
246 validate_html_element(&element, &[], &[]),
247 Err(MarkupError::InvalidElement {
248 attributes: Default::default(),
249 children: [("div".into(), [ChildError::NotAllowed].into())].into(),
250 })
251 );
252 }
253 }
254
255 mod html {
256 use super::*;
257
258 #[test]
259 fn validate_valid_element() {
260 let element = create_element("html", vec![], vec![]);
261
262 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
263 }
264
265 #[test]
266 fn validate_valid_children() {
267 let element = create_element(
268 "html",
269 vec![],
270 vec![
271 create_element("head", vec![], vec![]),
272 create_element("body", vec![], vec![]),
273 ],
274 );
275
276 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
277 }
278 }
279
280 mod head {
281 use super::*;
282
283 #[test]
284 fn validate_valid_child() {
285 let element = create_element(
286 "head",
287 vec![],
288 vec![create_element("title", vec![], vec![])],
289 );
290
291 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
292 }
293
294 #[test]
295 fn validate_invalid_child() {
296 let element = create_element("head", vec![], vec![create_element("p", vec![], vec![])]);
297
298 assert_eq!(
299 validate_html_element(&element, &[], &[]),
300 Err(MarkupError::InvalidElement {
301 attributes: Default::default(),
302 children: [("p".into(), [ChildError::NotAllowed].into())].into(),
303 })
304 );
305 }
306 }
307
308 mod title {
309 use super::*;
310
311 #[test]
312 fn validate_invalid_child() {
313 let element =
314 create_element("title", vec![], vec![create_element("div", vec![], vec![])]);
315
316 assert_eq!(
317 validate_html_element(&element, &[], &[]),
318 Err(MarkupError::InvalidElement {
319 attributes: Default::default(),
320 children: [("div".into(), [ChildError::NotAllowed].into())].into(),
321 })
322 );
323 }
324 }
325
326 mod ul {
327 use super::*;
328
329 #[test]
330 fn validate_valid_child() {
331 let element = create_element("ul", vec![], vec![create_element("li", vec![], vec![])]);
332
333 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
334 }
335
336 #[test]
337 fn validate_invalid_child() {
338 let element = create_element("ul", vec![], vec![create_element("p", vec![], vec![])]);
339
340 assert_eq!(
341 validate_html_element(&element, &[], &[]),
342 Err(MarkupError::InvalidElement {
343 attributes: Default::default(),
344 children: [("p".into(), [ChildError::NotAllowed].into())].into(),
345 })
346 );
347 }
348 }
349
350 mod table {
351 use super::*;
352
353 #[test]
354 fn validate_valid_child() {
355 let element =
356 create_element("table", vec![], vec![create_element("tr", vec![], vec![])]);
357
358 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
359 }
360
361 #[test]
362 fn validate_invalid_child() {
363 let element =
364 create_element("table", vec![], vec![create_element("p", vec![], vec![])]);
365
366 assert_eq!(
367 validate_html_element(&element, &[], &[]),
368 Err(MarkupError::InvalidElement {
369 attributes: Default::default(),
370 children: [("p".into(), [ChildError::NotAllowed].into())].into(),
371 })
372 );
373 }
374 }
375
376 mod tr {
377 use super::*;
378
379 #[test]
380 fn validate_valid_children() {
381 let element = create_element(
382 "tr",
383 vec![],
384 vec![
385 create_element("th", vec![], vec![]),
386 create_element("td", vec![], vec![]),
387 ],
388 );
389
390 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
391 }
392 }
393
394 mod form {
395 use super::*;
396
397 #[test]
398 fn validate_valid_attributes() {
399 let element = create_element("form", vec![("action", "/"), ("method", "post")], vec![]);
400
401 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
402 }
403
404 #[test]
405 fn validate_valid_child() {
406 let element = create_element(
407 "form",
408 vec![],
409 vec![create_element("input", vec![], vec![])],
410 );
411
412 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
413 }
414 }
415
416 mod img {
417 use super::*;
418
419 #[test]
420 fn validate_valid_attributes() {
421 let element = create_element(
422 "img",
423 vec![("src", "img.png"), ("alt", "description")],
424 vec![],
425 );
426
427 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
428 }
429 }
430
431 mod picture {
432 use super::*;
433
434 #[test]
435 fn validate_valid_element() {
436 let element = create_element("picture", vec![], vec![]);
437
438 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
439 }
440
441 #[test]
442 fn validate_valid_children() {
443 let element = create_element(
444 "picture",
445 vec![],
446 vec![
447 create_element("source", vec![], vec![]),
448 create_element("img", vec![], vec![]),
449 ],
450 );
451
452 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
453 }
454
455 #[test]
456 fn validate_invalid_child() {
457 let element =
458 create_element("picture", vec![], vec![create_element("p", vec![], vec![])]);
459
460 assert_eq!(
461 validate_html_element(&element, &[], &[]),
462 Err(MarkupError::InvalidElement {
463 attributes: Default::default(),
464 children: [("p".into(), [ChildError::NotAllowed].into())].into(),
465 })
466 );
467 }
468 }
469
470 mod video {
471 use super::*;
472
473 #[test]
474 fn validate_valid_attributes() {
475 let element =
476 create_element("video", vec![("src", "vid.mp4"), ("controls", "")], vec![]);
477
478 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
479 }
480
481 #[test]
482 fn validate_valid_child() {
483 let element = create_element(
484 "video",
485 vec![],
486 vec![create_element("track", vec![], vec![])],
487 );
488
489 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
490 }
491 }
492
493 mod meta {
494 use super::*;
495
496 #[test]
497 fn validate_valid_name_content() {
498 let element = create_element(
499 "meta",
500 vec![("name", "description"), ("content", "stuff")],
501 vec![],
502 );
503
504 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
505 }
506
507 #[test]
508 fn validate_valid_charset() {
509 let element = create_element("meta", vec![("charset", "utf-8")], vec![]);
510
511 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
512 }
513
514 #[test]
515 fn validate_valid_property() {
516 let element = create_element("meta", vec![("property", "og:image")], vec![]);
517
518 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
519 }
520 }
521
522 mod link {
523 use super::*;
524
525 #[test]
526 fn validate_valid_attributes() {
527 let element = create_element(
528 "link",
529 vec![("rel", "stylesheet"), ("href", "style.css")],
530 vec![],
531 );
532
533 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
534 }
535 }
536
537 mod noscript {
538 use super::*;
539
540 #[test]
541 fn validate_valid_element() {
542 let element = create_element("noscript", vec![], vec![]);
543
544 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
545 }
546
547 #[test]
548 fn validate_valid_flow_child() {
549 let element = create_element(
550 "noscript",
551 vec![],
552 vec![create_element("div", vec![], vec![])],
553 );
554
555 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
556 }
557
558 #[test]
559 fn validate_valid_head_child() {
560 let element = create_element(
561 "noscript",
562 vec![],
563 vec![create_element("link", vec![], vec![])],
564 );
565
566 assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
567 }
568
569 #[test]
570 fn validate_invalid_child() {
571 let element = create_element(
572 "noscript",
573 vec![],
574 vec![create_element("title", vec![], vec![])],
575 );
576
577 assert_eq!(
578 validate_html_element(&element, &[], &[]),
579 Err(MarkupError::InvalidElement {
580 attributes: Default::default(),
581 children: [("title".into(), [ChildError::NotAllowed].into())].into(),
582 })
583 );
584 }
585 }
586}