2 * Copyright (c) 2016 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.yangtools.yang.data.codec.xml;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
13 import java.util.Collection;
14 import java.util.List;
15 import javax.xml.stream.XMLOutputFactory;
16 import javax.xml.transform.dom.DOMResult;
17 import org.custommonkey.xmlunit.Diff;
18 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
19 import org.custommonkey.xmlunit.IgnoreTextAndAttributeValuesDifferenceListener;
20 import org.custommonkey.xmlunit.XMLUnit;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.junit.runners.Parameterized;
24 import org.opendaylight.yangtools.util.xml.UntrustedXML;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.QNameModule;
27 import org.opendaylight.yangtools.yang.common.Revision;
28 import org.opendaylight.yangtools.yang.common.Uint32;
29 import org.opendaylight.yangtools.yang.common.XMLNamespace;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
33 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
35 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
36 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
38 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
39 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
40 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
41 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
43 @RunWith(Parameterized.class)
44 public class NormalizedNodeXmlTranslationTest extends AbstractXmlTest {
45 private final EffectiveModelContext schema;
47 @Parameterized.Parameters()
48 public static Collection<Object[]> data() {
49 return List.of(new Object[][] {
50 { "/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok.xml", augmentChoiceHell() },
51 { "/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok2.xml", null },
52 { "/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok3.xml", augmentChoiceHell2() },
53 { "/schema/test.yang", "/schema/simple.xml", null },
54 { "/schema/test.yang", "/schema/simple2.xml", null },
55 // TODO check attributes
56 { "/schema/test.yang", "/schema/simple_xml_with_attributes.xml", withAttributes() }
60 private static final QNameModule MODULE = QNameModule.create(
61 XMLNamespace.of("urn:opendaylight:params:xml:ns:yang:controller:test"), Revision.of("2014-03-13"));
63 private static ContainerNode augmentChoiceHell2() {
64 final var container = getNodeIdentifier("container");
65 final var augmentChoice1QName = QName.create(container.getNodeType(), "augment-choice1");
66 final var augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
67 final var containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
68 final var leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
70 return Builders.containerBuilder()
71 .withNodeIdentifier(container)
72 .withChild(Builders.choiceBuilder()
73 .withNodeIdentifier(new NodeIdentifier(augmentChoice1QName))
74 .withChild(Builders.choiceBuilder()
75 .withNodeIdentifier(new NodeIdentifier(augmentChoice2QName))
76 .withChild(Builders.containerBuilder()
77 .withNodeIdentifier(new NodeIdentifier(containerQName))
78 .withChild(ImmutableNodes.leafNode(leafQName, "leaf-value"))
85 private static ContainerNode withAttributes() {
86 return Builders.containerBuilder()
87 .withNodeIdentifier(getNodeIdentifier("container"))
88 .withChild(Builders.mapBuilder()
89 .withNodeIdentifier(getNodeIdentifier("list"))
90 .withChild(Builders.mapEntryBuilder()
91 .withNodeIdentifier(NodeIdentifierWithPredicates.of(getNodeIdentifier("list").getNodeType(),
92 getNodeIdentifier("uint32InList").getNodeType(), Uint32.valueOf(3)))
93 .withChild(Builders.leafBuilder()
94 .withNodeIdentifier(getNodeIdentifier("uint32InList"))
95 .withValue(Uint32.valueOf(3))
99 .withChild(Builders.leafBuilder()
100 .withNodeIdentifier(getNodeIdentifier("boolean"))
101 .withValue(Boolean.FALSE)
103 .withChild(Builders.leafSetBuilder()
104 .withNodeIdentifier(getNodeIdentifier("leafList"))
105 .withChild(Builders.leafSetEntryBuilder()
106 .withNodeIdentifier(new NodeWithValue<>(getNodeIdentifier("leafList").getNodeType(), "a"))
113 private static ContainerNode augmentChoiceHell() {
114 return Builders.containerBuilder()
115 .withNodeIdentifier(getNodeIdentifier("container"))
116 .withChild(Builders.choiceBuilder()
117 .withNodeIdentifier(getNodeIdentifier("ch2"))
118 .withChild(Builders.leafBuilder()
119 .withNodeIdentifier(getNodeIdentifier("c2Leaf"))
122 .withChild(Builders.choiceBuilder()
123 .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
124 .withChild(Builders.leafBuilder()
125 .withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
130 .withChild(Builders.choiceBuilder()
131 .withNodeIdentifier(getNodeIdentifier("ch3"))
132 .withChild(Builders.leafBuilder()
133 .withNodeIdentifier(getNodeIdentifier("c3Leaf"))
137 .withChild(Builders.leafBuilder()
138 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
139 .withValue("augment")
141 .withChild(Builders.choiceBuilder()
142 .withNodeIdentifier(getNodeIdentifier("ch"))
143 .withChild(Builders.leafBuilder()
144 .withNodeIdentifier(getNodeIdentifier("c1Leaf")).withValue("1")
146 .withChild(Builders.leafBuilder()
147 .withNodeIdentifier(getNodeIdentifier("c1Leaf_AnotherAugment"))
150 .withChild(Builders.choiceBuilder()
151 .withNodeIdentifier(getNodeIdentifier("deepChoice"))
152 .withChild(Builders.leafBuilder()
153 .withNodeIdentifier(getNodeIdentifier("deepLeafc1"))
161 private static NodeIdentifier getNodeIdentifier(final String localName) {
162 return new NodeIdentifier(QName.create(MODULE, localName));
165 private final ContainerNode expectedNode;
166 private final String xmlPath;
168 public NormalizedNodeXmlTranslationTest(final String yangPath, final String xmlPath,
169 final ContainerNode expectedNode) {
170 schema = YangParserTestUtils.parseYangResource(yangPath);
171 this.xmlPath = xmlPath;
172 this.expectedNode = expectedNode;
176 public void testTranslationRepairing() throws Exception {
177 testTranslation(TestFactories.REPAIRING_OUTPUT_FACTORY);
181 public void testTranslation() throws Exception {
182 testTranslation(TestFactories.DEFAULT_OUTPUT_FACTORY);
185 private void testTranslation(final XMLOutputFactory factory) throws Exception {
186 final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream(xmlPath);
188 final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
190 final var result = new NormalizationResultHolder();
191 final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
192 final var xmlParser = XmlParserStream.create(streamWriter,
193 Inference.ofDataTreePath(schema, QName.create(MODULE, "container")));
194 xmlParser.parse(reader);
196 final var built = result.getResult().data();
197 assertNotNull(built);
199 if (expectedNode != null) {
200 assertEquals(expectedNode, built);
203 final var document = UntrustedXML.newDocumentBuilder().newDocument();
204 final var domResult = new DOMResult(document);
205 final var xmlStreamWriter = factory.createXMLStreamWriter(domResult);
206 final var xmlNormalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlStreamWriter, schema);
207 final var normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(xmlNormalizedNodeStreamWriter);
208 normalizedNodeWriter.write(built);
210 final var doc = loadDocument(xmlPath);
212 XMLUnit.setIgnoreWhitespace(true);
213 XMLUnit.setIgnoreComments(true);
214 XMLUnit.setIgnoreAttributeOrder(true);
215 XMLUnit.setNormalize(true);
217 final String expectedXml = toString(doc.getDocumentElement());
218 final String serializedXml = toString(domResult.getNode());
220 final Diff diff = new Diff(expectedXml, serializedXml);
221 diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
222 diff.overrideElementQualifier(new ElementNameAndTextQualifier());
224 // FIXME the comparison cannot be performed, since the qualifiers supplied by XMLUnit do not work correctly in
226 // We need to implement custom qualifier so that the element ordering does not mess the DIFF
227 // dd.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(100, true));
228 // assertTrue(dd.toString(), dd.similar());
230 // XMLAssert.assertXMLEqual(diff, true);