1extern crate alloc;
4
5use alloc::collections::{BTreeMap, BTreeSet};
6use muffy_document::html::Element;
7use muffy_validation_macro::html;
8
9html! {}
10
11#[derive(Clone, Debug, Eq, PartialEq)]
13pub enum ValidationError {
14 InvalidTag(String),
16 InvalidElement {
18 attributes: BTreeMap<String, BTreeSet<AttributeError>>,
20 children: BTreeMap<String, BTreeSet<ChildError>>,
22 },
23}
24
25#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
27pub enum AttributeError {
28 Invalid,
30}
31
32#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
34pub enum ChildError {
35 Invalid,
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use muffy_document::html::Node;
43 use std::sync::Arc;
44
45 fn create_element(
46 name: &str,
47 attributes: Vec<(&str, &str)>,
48 children: Vec<Element>,
49 ) -> Element {
50 Element::new(
51 name.to_owned(),
52 attributes
53 .into_iter()
54 .map(|(k, v)| (k.to_owned(), v.to_owned()))
55 .collect(),
56 children
57 .into_iter()
58 .map(|e| Arc::new(Node::Element(e)))
59 .collect(),
60 )
61 }
62
63 #[test]
64 fn validate_invalid_element_name() {
65 let element = create_element("invalid", vec![], vec![]);
66
67 assert_eq!(
68 validate_element(&element),
69 Err(ValidationError::InvalidTag("invalid".to_owned()))
70 );
71 }
72
73 mod div {
74 use super::*;
75
76 #[test]
77 fn validate_valid_element() {
78 let element = create_element("div", vec![], vec![]);
79
80 assert_eq!(validate_element(&element), Ok(()));
81 }
82
83 #[test]
84 fn validate_valid_attributes() {
85 let element = create_element("div", vec![("id", "foo"), ("class", "bar")], vec![]);
86
87 assert_eq!(validate_element(&element), Ok(()));
88 }
89
90 #[test]
91 fn validate_invalid_attribute() {
92 let element = create_element("div", vec![("invalid", "foo")], vec![]);
93
94 assert_eq!(
95 validate_element(&element),
96 Err(ValidationError::InvalidElement {
97 attributes: [("invalid".into(), [AttributeError::Invalid].into())].into(),
98 children: Default::default(),
99 })
100 );
101 }
102
103 #[test]
104 fn validate_multiple_invalid_attributes() {
105 let element = create_element(
106 "div",
107 vec![("invalid-one", "foo"), ("invalid-two", "bar")],
108 vec![],
109 );
110
111 assert_eq!(
112 validate_element(&element),
113 Err(ValidationError::InvalidElement {
114 attributes: [
115 ("invalid-one".into(), [AttributeError::Invalid].into()),
116 ("invalid-two".into(), [AttributeError::Invalid].into()),
117 ]
118 .into(),
119 children: Default::default(),
120 })
121 );
122 }
123
124 #[test]
125 fn validate_valid_child() {
126 let element = create_element("div", vec![], vec![create_element("p", vec![], vec![])]);
127
128 assert_eq!(validate_element(&element), Ok(()));
129 }
130 }
131
132 mod p {
133 use super::*;
134
135 #[test]
136 fn validate_valid_element() {
137 let element = create_element("p", vec![], vec![]);
138
139 assert_eq!(validate_element(&element), Ok(()));
140 }
141
142 #[test]
143 fn validate_invalid_child() {
144 let element = create_element("p", vec![], vec![create_element("div", vec![], vec![])]);
145
146 assert_eq!(
147 validate_element(&element),
148 Err(ValidationError::InvalidElement {
149 attributes: Default::default(),
150 children: [("div".into(), [ChildError::Invalid].into())].into(),
151 })
152 );
153 }
154
155 #[test]
156 fn validate_multiple_invalid_children() {
157 let element = create_element(
158 "p",
159 vec![],
160 vec![
161 create_element("div", vec![], vec![]),
162 create_element("table", vec![], vec![]),
163 ],
164 );
165
166 assert_eq!(
167 validate_element(&element),
168 Err(ValidationError::InvalidElement {
169 attributes: Default::default(),
170 children: [
171 ("div".into(), [ChildError::Invalid].into()),
172 ("table".into(), [ChildError::Invalid].into()),
173 ]
174 .into(),
175 })
176 );
177 }
178 }
179
180 mod html {
181 use super::*;
182
183 #[test]
184 fn validate_valid_element() {
185 let element = create_element("html", vec![], vec![]);
186
187 assert_eq!(validate_element(&element), Ok(()));
188 }
189
190 #[test]
191 fn validate_valid_children() {
192 let element = create_element(
193 "html",
194 vec![],
195 vec![
196 create_element("head", vec![], vec![]),
197 create_element("body", vec![], vec![]),
198 ],
199 );
200
201 assert_eq!(validate_element(&element), Ok(()));
202 }
203 }
204
205 mod head {
206 use super::*;
207
208 #[test]
209 fn validate_valid_child() {
210 let element = create_element(
211 "head",
212 vec![],
213 vec![create_element("title", vec![], vec![])],
214 );
215
216 assert_eq!(validate_element(&element), Ok(()));
217 }
218
219 #[test]
220 fn validate_invalid_child() {
221 let element = create_element("head", vec![], vec![create_element("p", vec![], vec![])]);
222
223 assert_eq!(
224 validate_element(&element),
225 Err(ValidationError::InvalidElement {
226 attributes: Default::default(),
227 children: [("p".into(), [ChildError::Invalid].into())].into(),
228 })
229 );
230 }
231 }
232
233 mod title {
234 use super::*;
235
236 #[test]
237 fn validate_invalid_child() {
238 let element =
239 create_element("title", vec![], vec![create_element("div", vec![], vec![])]);
240
241 assert_eq!(
242 validate_element(&element),
243 Err(ValidationError::InvalidElement {
244 attributes: Default::default(),
245 children: [("div".into(), [ChildError::Invalid].into())].into(),
246 })
247 );
248 }
249 }
250
251 mod ul {
252 use super::*;
253
254 #[test]
255 fn validate_valid_child() {
256 let element = create_element("ul", vec![], vec![create_element("li", vec![], vec![])]);
257
258 assert_eq!(validate_element(&element), Ok(()));
259 }
260
261 #[test]
262 fn validate_invalid_child() {
263 let element = create_element("ul", vec![], vec![create_element("p", vec![], vec![])]);
264
265 assert_eq!(
266 validate_element(&element),
267 Err(ValidationError::InvalidElement {
268 attributes: Default::default(),
269 children: [("p".into(), [ChildError::Invalid].into())].into(),
270 })
271 );
272 }
273 }
274
275 mod table {
276 use super::*;
277
278 #[test]
279 fn validate_valid_child() {
280 let element =
281 create_element("table", vec![], vec![create_element("tr", vec![], vec![])]);
282
283 assert_eq!(validate_element(&element), Ok(()));
284 }
285
286 #[test]
287 fn validate_invalid_child() {
288 let element =
289 create_element("table", vec![], vec![create_element("p", vec![], vec![])]);
290
291 assert_eq!(
292 validate_element(&element),
293 Err(ValidationError::InvalidElement {
294 attributes: Default::default(),
295 children: [("p".into(), [ChildError::Invalid].into())].into(),
296 })
297 );
298 }
299 }
300
301 mod tr {
302 use super::*;
303
304 #[test]
305 fn validate_valid_children() {
306 let element = create_element(
307 "tr",
308 vec![],
309 vec![
310 create_element("th", vec![], vec![]),
311 create_element("td", vec![], vec![]),
312 ],
313 );
314
315 assert_eq!(validate_element(&element), Ok(()));
316 }
317 }
318
319 mod form {
320 use super::*;
321
322 #[test]
323 fn validate_valid_attributes() {
324 let element = create_element("form", vec![("action", "/"), ("method", "post")], vec![]);
325
326 assert_eq!(validate_element(&element), Ok(()));
327 }
328
329 #[test]
330 fn validate_valid_child() {
331 let element = create_element(
332 "form",
333 vec![],
334 vec![create_element("input", vec![], vec![])],
335 );
336
337 assert_eq!(validate_element(&element), Ok(()));
338 }
339 }
340
341 mod img {
342 use super::*;
343
344 #[test]
345 fn validate_valid_attributes() {
346 let element = create_element(
347 "img",
348 vec![("src", "img.png"), ("alt", "description")],
349 vec![],
350 );
351
352 assert_eq!(validate_element(&element), Ok(()));
353 }
354 }
355
356 mod video {
357 use super::*;
358
359 #[test]
360 fn validate_valid_attributes() {
361 let element =
362 create_element("video", vec![("src", "vid.mp4"), ("controls", "")], vec![]);
363
364 assert_eq!(validate_element(&element), Ok(()));
365 }
366
367 #[test]
368 fn validate_valid_child() {
369 let element = create_element(
370 "video",
371 vec![],
372 vec![create_element("track", vec![], vec![])],
373 );
374
375 assert_eq!(validate_element(&element), Ok(()));
376 }
377 }
378
379 mod meta {
380 use super::*;
381
382 #[test]
383 fn validate_valid_name_content() {
384 let element = create_element(
385 "meta",
386 vec![("name", "description"), ("content", "stuff")],
387 vec![],
388 );
389
390 assert_eq!(validate_element(&element), Ok(()));
391 }
392
393 #[test]
394 fn validate_valid_charset() {
395 let element = create_element("meta", vec![("charset", "utf-8")], vec![]);
396
397 assert_eq!(validate_element(&element), Ok(()));
398 }
399 }
400
401 mod link {
402 use super::*;
403
404 #[test]
405 fn validate_valid_attributes() {
406 let element = create_element(
407 "link",
408 vec![("rel", "stylesheet"), ("href", "style.css")],
409 vec![],
410 );
411
412 assert_eq!(validate_element(&element), Ok(()));
413 }
414 }
415}