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 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}