1// Copyright (c) 2017 Astro <astro@spaceboyz.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use minidom::{Element, Node};
8
9pub trait NamespaceAwareCompare {
10 /// Namespace-aware comparison for tests
11 fn compare_to(&self, other: &Self) -> bool;
12}
13
14impl NamespaceAwareCompare for Node {
15 fn compare_to(&self, other: &Self) -> bool {
16 match (self, other) {
17 (&Node::Element(ref elem1), &Node::Element(ref elem2)) => {
18 Element::compare_to(elem1, elem2)
19 }
20 (&Node::Text(ref text1), &Node::Text(ref text2)) => text1 == text2,
21 _ => false,
22 }
23 }
24}
25
26impl NamespaceAwareCompare for Element {
27 fn compare_to(&self, other: &Self) -> bool {
28 if self.name() == other.name() && self.ns() == other.ns() && self.attrs().eq(other.attrs())
29 {
30 let child_elems = self.children().count();
31 let text_is_whitespace = self
32 .texts()
33 .all(|text| text.chars().all(char::is_whitespace));
34 if child_elems > 0 && text_is_whitespace {
35 // Ignore all the whitespace text nodes
36 self.children()
37 .zip(other.children())
38 .all(|(node1, node2)| node1.compare_to(node2))
39 } else {
40 // Compare with text nodes
41 self.nodes()
42 .zip(other.nodes())
43 .all(|(node1, node2)| node1.compare_to(node2))
44 }
45 } else {
46 false
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::Element;
55
56 #[test]
57 fn simple() {
58 let elem1: Element = "<a a='b'>x <l/> 3</a>".parse().unwrap();
59 let elem2: Element = "<a a='b'>x <l/> 3</a>".parse().unwrap();
60 assert!(elem1.compare_to(&elem2));
61 }
62
63 #[test]
64 fn wrong_attr_name() {
65 let elem1: Element = "<a a='b'>x 3</a>".parse().unwrap();
66 let elem2: Element = "<a c='b'>x 3</a>".parse().unwrap();
67 assert!(!elem1.compare_to(&elem2));
68 }
69
70 #[test]
71 fn wrong_attr_value() {
72 let elem1: Element = "<a a='b'>x 3</a>".parse().unwrap();
73 let elem2: Element = "<a a='c'>x 3</a>".parse().unwrap();
74 assert!(!elem1.compare_to(&elem2));
75 }
76
77 #[test]
78 fn attr_order() {
79 let elem1: Element = "<e1 a='b' c='d'/>".parse().unwrap();
80 let elem2: Element = "<e1 c='d' a='b'/>".parse().unwrap();
81 assert!(elem1.compare_to(&elem2));
82 }
83
84 #[test]
85 fn wrong_texts() {
86 let elem1: Element = "<e1>foo</e1>".parse().unwrap();
87 let elem2: Element = "<e1>bar</e1>".parse().unwrap();
88 assert!(!elem1.compare_to(&elem2));
89 }
90
91 #[test]
92 fn children() {
93 let elem1: Element = "<e1><foo/><bar/></e1>".parse().unwrap();
94 let elem2: Element = "<e1><foo/><bar/></e1>".parse().unwrap();
95 assert!(elem1.compare_to(&elem2));
96 }
97
98 #[test]
99 fn wrong_children() {
100 let elem1: Element = "<e1><foo/></e1>".parse().unwrap();
101 let elem2: Element = "<e1><bar/></e1>".parse().unwrap();
102 assert!(!elem1.compare_to(&elem2));
103 }
104
105 #[test]
106 fn xmlns_wrong() {
107 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
108 let elem2: Element = "<e1 xmlns='ns2'><foo/></e1>".parse().unwrap();
109 assert!(!elem1.compare_to(&elem2));
110 }
111
112 #[test]
113 fn xmlns_other_prefix() {
114 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
115 let elem2: Element = "<x:e1 xmlns:x='ns1'><x:foo/></x:e1>".parse().unwrap();
116 assert!(elem1.compare_to(&elem2));
117 }
118
119 #[test]
120 fn xmlns_dup() {
121 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
122 let elem2: Element = "<e1 xmlns='ns1'><foo xmlns='ns1'/></e1>".parse().unwrap();
123 assert!(elem1.compare_to(&elem2));
124 }
125}