compare_elements.rs

  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}