Move netconf.util.xml to netconf-client
[netconf.git] / protocol / netconf-test-util / src / main / java / org / opendaylight / netconf / test / util / NetconfXmlUnitRecursiveQualifier.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.test.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
14 import org.custommonkey.xmlunit.ElementQualifier;
15 import org.w3c.dom.Element;
16 import org.w3c.dom.Node;
17 import org.w3c.dom.NodeList;
18
19 /**
20  * Custom xmlunit qualifier that doesn't care about order when deeper in the recursion
21  * defaults to comparing element name and text content.
22  */
23 public class NetconfXmlUnitRecursiveQualifier implements ElementQualifier {
24     private final ElementQualifier qualifier;
25
26     public NetconfXmlUnitRecursiveQualifier() {
27         this(new ElementNameAndTextQualifier());
28     }
29
30     public NetconfXmlUnitRecursiveQualifier(final ElementQualifier qualifier) {
31         this.qualifier = requireNonNull(qualifier);
32     }
33
34     @Override
35     public boolean qualifyForComparison(final Element currentControl,
36                                         final Element currentTest) {
37         return compareNodes(currentControl, currentTest);
38     }
39
40     @SuppressWarnings("checkstyle:IllegalCatch")
41     @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION")
42     private boolean compareNodes(final Node currentControl, final Node currentTest) {
43         try {
44             if (!qualifier.qualifyForComparison((Element) currentControl, (Element) currentTest)) {
45                 return false;
46             }
47
48             NodeList controlNodes;
49             NodeList testNodes;
50
51             if (currentControl.hasChildNodes() && currentTest.hasChildNodes()) {
52                 controlNodes = currentControl.getChildNodes();
53                 testNodes = currentTest.getChildNodes();
54             } else {
55                 return !currentControl.hasChildNodes() && !currentTest.hasChildNodes();
56             }
57
58             return countNodesWithoutConsecutiveTextNodes(controlNodes)
59                     == countNodesWithoutConsecutiveTextNodes(testNodes) && checkChildren(controlNodes, testNodes);
60
61         } catch (Exception e) {
62             return false;
63         }
64     }
65
66     private boolean checkChildren(final NodeList controlNodes, final NodeList testNodes) {
67         for (int i = 0; i < controlNodes.getLength(); i++) {
68             boolean matchFound = false;
69             for (int j = 0; j < testNodes.getLength(); j++) {
70                 Node controlNode = controlNodes.item(i);
71                 Node testNode = testNodes.item(j);
72
73                 if (controlNode.getNodeType() != testNode.getNodeType()) {
74                     continue;
75                 }
76
77                 if (controlNode.getNodeType() == Node.TEXT_NODE) {
78                     if (concatenateText(controlNode).equals(concatenateText(testNode))) {
79                         matchFound = true;
80                         break;
81                     }
82
83                 } else if (compareNodes(controlNode, testNode)) {
84                     matchFound = true;
85                     break;
86                 }
87             }
88             if (!matchFound) {
89                 return false;
90             }
91         }
92
93         return true;
94     }
95
96     private static String concatenateText(final Node textNode) {
97         StringBuilder builder = new StringBuilder();
98         Node next = textNode;
99
100         do {
101             if (next.getNodeValue() != null) {
102                 builder.append(next.getNodeValue().trim());
103                 next = next.getNextSibling();
104             }
105         } while (next != null && next.getNodeType() == Node.TEXT_NODE);
106
107         return builder.toString();
108     }
109
110     private static int countNodesWithoutConsecutiveTextNodes(final NodeList nodeList) {
111         int count = 0;
112         boolean lastNodeWasText = false;
113         for (int i = 0, length = nodeList.getLength(); i < length; i++) {
114             Node node = nodeList.item(i);
115             if (!lastNodeWasText || node.getNodeType() != Node.TEXT_NODE) {
116                 count++;
117             }
118             lastNodeWasText = node.getNodeType() == Node.TEXT_NODE;
119         }
120         return count;
121     }
122 }