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::{Node, Element};
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 (&Node::Text(ref text1), &Node::Text(ref text2)) =>
20 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() &&
29 self.ns() == other.ns() &&
30 self.attrs().eq(other.attrs())
31 {
32 let child_elems = self.children().count();
33 let text_is_whitespace = self.texts()
34 .all(|text| text.chars().all(char::is_whitespace));
35 if child_elems > 0 && text_is_whitespace {
36 // Ignore all the whitespace text nodes
37 self.children().zip(other.children())
38 .all(|(node1, node2)| node1.compare_to(node2))
39 } else {
40 // Compare with text nodes
41 self.nodes().zip(other.nodes())
42 .all(|(node1, node2)| node1.compare_to(node2))
43 }
44 } else {
45 false
46 }
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use minidom::Element;
54
55 #[test]
56 fn simple() {
57 let elem1: Element = "<a a='b'>x <l/> 3</a>".parse().unwrap();
58 let elem2: Element = "<a a='b'>x <l/> 3</a>".parse().unwrap();
59 assert!(elem1.compare_to(&elem2));
60 }
61
62 #[test]
63 fn wrong_attr_name() {
64 let elem1: Element = "<a a='b'>x 3</a>".parse().unwrap();
65 let elem2: Element = "<a c='b'>x 3</a>".parse().unwrap();
66 assert!(!elem1.compare_to(&elem2));
67 }
68
69 #[test]
70 fn wrong_attr_value() {
71 let elem1: Element = "<a a='b'>x 3</a>".parse().unwrap();
72 let elem2: Element = "<a a='c'>x 3</a>".parse().unwrap();
73 assert!(!elem1.compare_to(&elem2));
74 }
75
76 #[test]
77 fn attr_order() {
78 let elem1: Element = "<e1 a='b' c='d'/>".parse().unwrap();
79 let elem2: Element = "<e1 c='d' a='b'/>".parse().unwrap();
80 assert!(elem1.compare_to(&elem2));
81 }
82
83 #[test]
84 fn wrong_texts() {
85 let elem1: Element = "<e1>foo</e1>".parse().unwrap();
86 let elem2: Element = "<e1>bar</e1>".parse().unwrap();
87 assert!(!elem1.compare_to(&elem2));
88 }
89
90 #[test]
91 fn children() {
92 let elem1: Element = "<e1><foo/><bar/></e1>".parse().unwrap();
93 let elem2: Element = "<e1><foo/><bar/></e1>".parse().unwrap();
94 assert!(elem1.compare_to(&elem2));
95 }
96
97 #[test]
98 fn wrong_children() {
99 let elem1: Element = "<e1><foo/></e1>".parse().unwrap();
100 let elem2: Element = "<e1><bar/></e1>".parse().unwrap();
101 assert!(!elem1.compare_to(&elem2));
102 }
103
104 #[test]
105 fn xmlns_wrong() {
106 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
107 let elem2: Element = "<e1 xmlns='ns2'><foo/></e1>".parse().unwrap();
108 assert!(!elem1.compare_to(&elem2));
109 }
110
111 #[test]
112 fn xmlns_other_prefix() {
113 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
114 let elem2: Element = "<x:e1 xmlns:x='ns1'><x:foo/></x:e1>".parse().unwrap();
115 assert!(elem1.compare_to(&elem2));
116 }
117
118 #[test]
119 fn xmlns_dup() {
120 let elem1: Element = "<e1 xmlns='ns1'><foo/></e1>".parse().unwrap();
121 let elem2: Element = "<e1 xmlns='ns1'><foo xmlns='ns1'/></e1>".parse().unwrap();
122 assert!(elem1.compare_to(&elem2));
123 }
124}