Add NetconfXmlUnitRecursiveQualifier to netconf-util. 06/20006/5
authorTomas Cere <tcere@cisco.com>
Mon, 11 May 2015 08:03:18 +0000 (10:03 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 12 May 2015 07:41:53 +0000 (07:41 +0000)
XmlUnit's RecursiveElementNameAndTextQualifier has trouble with non-trivial xml's and
element order in bigger depths.
This adds our own qualifier based on XmlUnit's implementation.

Change-Id: Ie89e84813e11cb2af7c9d3c0c6d80377816f79a7
Signed-off-by: Tomas Cere <tcere@cisco.com>
opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/NetconfXmlUnitRecursiveQualifier.java [new file with mode: 0644]

diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/NetconfXmlUnitRecursiveQualifier.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/NetconfXmlUnitRecursiveQualifier.java
new file mode 100644 (file)
index 0000000..fb41600
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.test;
+
+import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
+import org.custommonkey.xmlunit.ElementQualifier;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Custom xmlunit qualifier that doesn't care about order when deeper in the recursion
+ * defaults to comparing element name and text content
+ */
+public class NetconfXmlUnitRecursiveQualifier implements ElementQualifier {
+
+    private final ElementQualifier qualifier;
+
+    public NetconfXmlUnitRecursiveQualifier() {
+        this.qualifier = new ElementNameAndTextQualifier();
+    }
+
+    public NetconfXmlUnitRecursiveQualifier(final ElementQualifier qualifier) {
+        this.qualifier = qualifier;
+    }
+
+    @Override
+    public boolean qualifyForComparison(Element currentControl,
+                                        Element currentTest) {
+        return compareNodes(currentControl, currentTest);
+    }
+
+    private boolean compareNodes(Node currentControl, Node currentTest) {
+        try {
+
+            if (!qualifier.qualifyForComparison((Element) currentControl,
+                    (Element) currentTest)) {
+                return false;
+            }
+
+            NodeList controlNodes;
+            NodeList testNodes;
+
+            if (currentControl.hasChildNodes() && currentTest.hasChildNodes()) {
+                controlNodes = currentControl.getChildNodes();
+                testNodes = currentTest.getChildNodes();
+            } else {
+                return !(currentControl.hasChildNodes() || currentTest.hasChildNodes());
+            }
+
+            return (countNodesWithoutConsecutiveTextNodes(controlNodes) == countNodesWithoutConsecutiveTextNodes(testNodes))
+                    && checkChildren(controlNodes, testNodes);
+
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private boolean checkChildren(NodeList controlNodes, NodeList testNodes) {
+        for (int i = 0; i < controlNodes.getLength(); i++) {
+            boolean matchFound = false;
+            for (int j = 0; j < testNodes.getLength(); j++) {
+                Node controlNode = controlNodes.item(i);
+                Node testNode = testNodes.item(j);
+
+                if (controlNode.getNodeType() != testNode.getNodeType()) {
+                    continue;
+                }
+
+                if (controlNode.getNodeType() == Node.TEXT_NODE) {
+                    if (concatenateText(controlNode).equals(concatenateText(testNode))) {
+                        matchFound = true;
+                        break;
+                    }
+
+                } else if (compareNodes(controlNode, testNode)) {
+                    matchFound = true;
+                    break;
+                }
+            }
+            if (!matchFound) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static String concatenateText(Node textNode) {
+        StringBuilder builder = new StringBuilder();
+        Node next = textNode;
+
+        do {
+            if (next.getNodeValue() != null) {
+                builder.append(next.getNodeValue().trim());
+                next = next.getNextSibling();
+            }
+        } while (next != null && next.getNodeType() == Node.TEXT_NODE);
+
+        return builder.toString();
+    }
+
+    private static int countNodesWithoutConsecutiveTextNodes(NodeList l) {
+        int count = 0;
+        boolean lastNodeWasText = false;
+        final int length = l.getLength();
+        for (int i = 0; i < length; i++) {
+            Node n = l.item(i);
+            if (!lastNodeWasText || n.getNodeType() != Node.TEXT_NODE) {
+                count++;
+            }
+            lastNodeWasText = n.getNodeType() == Node.TEXT_NODE;
+        }
+        return count;
+    }
+}