2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netconf.test.util;
10 import static java.util.Objects.requireNonNull;
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;
20 * Custom xmlunit qualifier that doesn't care about order when deeper in the recursion
21 * defaults to comparing element name and text content.
23 public class NetconfXmlUnitRecursiveQualifier implements ElementQualifier {
24 private final ElementQualifier qualifier;
26 public NetconfXmlUnitRecursiveQualifier() {
27 this(new ElementNameAndTextQualifier());
30 public NetconfXmlUnitRecursiveQualifier(final ElementQualifier qualifier) {
31 this.qualifier = requireNonNull(qualifier);
35 public boolean qualifyForComparison(final Element currentControl,
36 final Element currentTest) {
37 return compareNodes(currentControl, currentTest);
40 @SuppressWarnings("checkstyle:IllegalCatch")
41 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION")
42 private boolean compareNodes(final Node currentControl, final Node currentTest) {
44 if (!qualifier.qualifyForComparison((Element) currentControl, (Element) currentTest)) {
48 NodeList controlNodes;
51 if (currentControl.hasChildNodes() && currentTest.hasChildNodes()) {
52 controlNodes = currentControl.getChildNodes();
53 testNodes = currentTest.getChildNodes();
55 return !currentControl.hasChildNodes() && !currentTest.hasChildNodes();
58 return countNodesWithoutConsecutiveTextNodes(controlNodes)
59 == countNodesWithoutConsecutiveTextNodes(testNodes) && checkChildren(controlNodes, testNodes);
61 } catch (Exception e) {
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);
73 if (controlNode.getNodeType() != testNode.getNodeType()) {
77 if (controlNode.getNodeType() == Node.TEXT_NODE) {
78 if (concatenateText(controlNode).equals(concatenateText(testNode))) {
83 } else if (compareNodes(controlNode, testNode)) {
96 private static String concatenateText(final Node textNode) {
97 StringBuilder builder = new StringBuilder();
101 if (next.getNodeValue() != null) {
102 builder.append(next.getNodeValue().trim());
103 next = next.getNextSibling();
105 } while (next != null && next.getNodeType() == Node.TEXT_NODE);
107 return builder.toString();
110 private static int countNodesWithoutConsecutiveTextNodes(final NodeList nodeList) {
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) {
118 lastNodeWasText = node.getNodeType() == Node.TEXT_NODE;