Skip to main content

muffy_validation/
lib.rs

1//! Document validation.
2
3extern 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 muffy_document::html::Node;
17    use regex::Regex;
18    use std::sync::Arc;
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_valid_child() {
135            let element = create_element("div", vec![], vec![create_element("p", vec![], vec![])]);
136
137            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
138        }
139    }
140
141    mod p {
142        use super::*;
143
144        #[test]
145        fn validate_valid_element() {
146            let element = create_element("p", vec![], vec![]);
147
148            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
149        }
150
151        #[test]
152        fn validate_invalid_child() {
153            let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
154
155            assert_eq!(
156                validate_html_element(&element, &[], &[]),
157                Err(MarkupError::InvalidElement {
158                    attributes: Default::default(),
159                    children: [("div".into(), [ChildError::NotAllowed].into())].into(),
160                })
161            );
162        }
163
164        #[test]
165        fn validate_multiple_invalid_children() {
166            let element = create_element(
167                "p",
168                vec![],
169                vec![
170                    create_element("div", vec![], vec![]),
171                    create_element("table", vec![], vec![]),
172                ],
173            );
174
175            assert_eq!(
176                validate_html_element(&element, &[], &[]),
177                Err(MarkupError::InvalidElement {
178                    attributes: Default::default(),
179                    children: [
180                        ("div".into(), [ChildError::NotAllowed].into()),
181                        ("table".into(), [ChildError::NotAllowed].into()),
182                    ]
183                    .into(),
184                })
185            );
186        }
187    }
188
189    mod html {
190        use super::*;
191
192        #[test]
193        fn validate_valid_element() {
194            let element = create_element("html", vec![], vec![]);
195
196            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
197        }
198
199        #[test]
200        fn validate_valid_children() {
201            let element = create_element(
202                "html",
203                vec![],
204                vec![
205                    create_element("head", vec![], vec![]),
206                    create_element("body", vec![], vec![]),
207                ],
208            );
209
210            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
211        }
212    }
213
214    mod head {
215        use super::*;
216
217        #[test]
218        fn validate_valid_child() {
219            let element = create_element(
220                "head",
221                vec![],
222                vec![create_element("title", vec![], vec![])],
223            );
224
225            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
226        }
227
228        #[test]
229        fn validate_invalid_child() {
230            let element = create_element("head", vec![], vec![create_element("p", vec![], vec![])]);
231
232            assert_eq!(
233                validate_html_element(&element, &[], &[]),
234                Err(MarkupError::InvalidElement {
235                    attributes: Default::default(),
236                    children: [("p".into(), [ChildError::NotAllowed].into())].into(),
237                })
238            );
239        }
240    }
241
242    mod title {
243        use super::*;
244
245        #[test]
246        fn validate_invalid_child() {
247            let element =
248                create_element("title", vec![], vec![create_element("div", vec![], vec![])]);
249
250            assert_eq!(
251                validate_html_element(&element, &[], &[]),
252                Err(MarkupError::InvalidElement {
253                    attributes: Default::default(),
254                    children: [("div".into(), [ChildError::NotAllowed].into())].into(),
255                })
256            );
257        }
258    }
259
260    mod ul {
261        use super::*;
262
263        #[test]
264        fn validate_valid_child() {
265            let element = create_element("ul", vec![], vec![create_element("li", vec![], vec![])]);
266
267            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
268        }
269
270        #[test]
271        fn validate_invalid_child() {
272            let element = create_element("ul", vec![], vec![create_element("p", vec![], vec![])]);
273
274            assert_eq!(
275                validate_html_element(&element, &[], &[]),
276                Err(MarkupError::InvalidElement {
277                    attributes: Default::default(),
278                    children: [("p".into(), [ChildError::NotAllowed].into())].into(),
279                })
280            );
281        }
282    }
283
284    mod table {
285        use super::*;
286
287        #[test]
288        fn validate_valid_child() {
289            let element =
290                create_element("table", vec![], vec![create_element("tr", vec![], vec![])]);
291
292            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
293        }
294
295        #[test]
296        fn validate_invalid_child() {
297            let element =
298                create_element("table", vec![], vec![create_element("p", vec![], vec![])]);
299
300            assert_eq!(
301                validate_html_element(&element, &[], &[]),
302                Err(MarkupError::InvalidElement {
303                    attributes: Default::default(),
304                    children: [("p".into(), [ChildError::NotAllowed].into())].into(),
305                })
306            );
307        }
308    }
309
310    mod tr {
311        use super::*;
312
313        #[test]
314        fn validate_valid_children() {
315            let element = create_element(
316                "tr",
317                vec![],
318                vec![
319                    create_element("th", vec![], vec![]),
320                    create_element("td", vec![], vec![]),
321                ],
322            );
323
324            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
325        }
326    }
327
328    mod form {
329        use super::*;
330
331        #[test]
332        fn validate_valid_attributes() {
333            let element = create_element("form", vec![("action", "/"), ("method", "post")], vec![]);
334
335            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
336        }
337
338        #[test]
339        fn validate_valid_child() {
340            let element = create_element(
341                "form",
342                vec![],
343                vec![create_element("input", vec![], vec![])],
344            );
345
346            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
347        }
348    }
349
350    mod img {
351        use super::*;
352
353        #[test]
354        fn validate_valid_attributes() {
355            let element = create_element(
356                "img",
357                vec![("src", "img.png"), ("alt", "description")],
358                vec![],
359            );
360
361            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
362        }
363    }
364
365    mod video {
366        use super::*;
367
368        #[test]
369        fn validate_valid_attributes() {
370            let element =
371                create_element("video", vec![("src", "vid.mp4"), ("controls", "")], vec![]);
372
373            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
374        }
375
376        #[test]
377        fn validate_valid_child() {
378            let element = create_element(
379                "video",
380                vec![],
381                vec![create_element("track", vec![], vec![])],
382            );
383
384            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
385        }
386    }
387
388    mod meta {
389        use super::*;
390
391        #[test]
392        fn validate_valid_name_content() {
393            let element = create_element(
394                "meta",
395                vec![("name", "description"), ("content", "stuff")],
396                vec![],
397            );
398
399            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
400        }
401
402        #[test]
403        fn validate_valid_charset() {
404            let element = create_element("meta", vec![("charset", "utf-8")], vec![]);
405
406            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
407        }
408
409        #[test]
410        fn validate_valid_property() {
411            let element = create_element("meta", vec![("property", "og:image")], vec![]);
412
413            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
414        }
415    }
416
417    mod link {
418        use super::*;
419
420        #[test]
421        fn validate_valid_attributes() {
422            let element = create_element(
423                "link",
424                vec![("rel", "stylesheet"), ("href", "style.css")],
425                vec![],
426            );
427
428            assert_eq!(validate_html_element(&element, &[], &[]), Ok(()));
429        }
430    }
431}