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.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
13 import java.util.List;
14 import javax.xml.stream.XMLOutputFactory;
15 import javax.xml.transform.dom.DOMResult;
16 import org.custommonkey.xmlunit.Diff;
17 import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
18 import org.custommonkey.xmlunit.IgnoreTextAndAttributeValuesDifferenceListener;
19 import org.custommonkey.xmlunit.XMLUnit;
20 import org.junit.jupiter.params.ParameterizedTest;
21 import org.junit.jupiter.params.provider.Arguments;
22 import org.junit.jupiter.params.provider.MethodSource;
23 import org.opendaylight.yangtools.util.xml.UntrustedXML;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.common.QNameModule;
26 import org.opendaylight.yangtools.yang.common.Revision;
27 import org.opendaylight.yangtools.yang.common.Uint32;
28 import org.opendaylight.yangtools.yang.common.XMLNamespace;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
32 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
34 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
35 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
36 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
37 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
38 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
39 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
41 public class NormalizedNodeXmlTranslationTest extends AbstractXmlTest {
42 private static final QNameModule MODULE = QNameModule.create(
43 XMLNamespace.of("urn:opendaylight:params:xml:ns:yang:controller:test"), Revision.of("2014-03-13"));
45 private static ContainerNode augmentChoiceHell2() {
46 final var container = getNodeIdentifier("container");
47 final var augmentChoice1QName = QName.create(container.getNodeType(), "augment-choice1");
48 final var augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
49 final var containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
50 final var leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
52 return Builders.containerBuilder()
53 .withNodeIdentifier(container)
54 .withChild(Builders.choiceBuilder()
55 .withNodeIdentifier(new NodeIdentifier(augmentChoice1QName))
56 .withChild(Builders.choiceBuilder()
57 .withNodeIdentifier(new NodeIdentifier(augmentChoice2QName))
58 .withChild(Builders.containerBuilder()
59 .withNodeIdentifier(new NodeIdentifier(containerQName))
60 .withChild(ImmutableNodes.leafNode(leafQName, "leaf-value"))
67 private static ContainerNode withAttributes() {
68 return Builders.containerBuilder()
69 .withNodeIdentifier(getNodeIdentifier("container"))
70 .withChild(Builders.mapBuilder()
71 .withNodeIdentifier(getNodeIdentifier("list"))
72 .withChild(Builders.mapEntryBuilder()
73 .withNodeIdentifier(NodeIdentifierWithPredicates.of(getNodeIdentifier("list").getNodeType(),
74 getNodeIdentifier("uint32InList").getNodeType(), Uint32.valueOf(3)))
75 .withChild(Builders.leafBuilder()
76 .withNodeIdentifier(getNodeIdentifier("uint32InList"))
77 .withValue(Uint32.valueOf(3))
81 .withChild(Builders.leafBuilder()
82 .withNodeIdentifier(getNodeIdentifier("boolean"))
83 .withValue(Boolean.FALSE)
85 .withChild(Builders.leafSetBuilder()
86 .withNodeIdentifier(getNodeIdentifier("leafList"))
87 .withChild(Builders.leafSetEntryBuilder()
88 .withNodeIdentifier(new NodeWithValue<>(getNodeIdentifier("leafList").getNodeType(), "a"))
95 private static ContainerNode augmentChoiceHell() {
96 return Builders.containerBuilder()
97 .withNodeIdentifier(getNodeIdentifier("container"))
98 .withChild(Builders.choiceBuilder()
99 .withNodeIdentifier(getNodeIdentifier("ch2"))
100 .withChild(Builders.leafBuilder()
101 .withNodeIdentifier(getNodeIdentifier("c2Leaf"))
104 .withChild(Builders.choiceBuilder()
105 .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
106 .withChild(Builders.leafBuilder()
107 .withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
112 .withChild(Builders.choiceBuilder()
113 .withNodeIdentifier(getNodeIdentifier("ch3"))
114 .withChild(Builders.leafBuilder()
115 .withNodeIdentifier(getNodeIdentifier("c3Leaf"))
119 .withChild(Builders.leafBuilder()
120 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
121 .withValue("augment")
123 .withChild(Builders.choiceBuilder()
124 .withNodeIdentifier(getNodeIdentifier("ch"))
125 .withChild(Builders.leafBuilder()
126 .withNodeIdentifier(getNodeIdentifier("c1Leaf")).withValue("1")
128 .withChild(Builders.leafBuilder()
129 .withNodeIdentifier(getNodeIdentifier("c1Leaf_AnotherAugment"))
132 .withChild(Builders.choiceBuilder()
133 .withNodeIdentifier(getNodeIdentifier("deepChoice"))
134 .withChild(Builders.leafBuilder()
135 .withNodeIdentifier(getNodeIdentifier("deepLeafc1"))
143 private static NodeIdentifier getNodeIdentifier(final String localName) {
144 return new NodeIdentifier(QName.create(MODULE, localName));
148 @MethodSource("data")
149 void testTranslationRepairing(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
151 testTranslation(TestFactories.REPAIRING_OUTPUT_FACTORY, yangPath, xmlPath, expectedNode);
155 @MethodSource("data")
156 void testTranslation(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
158 testTranslation(TestFactories.DEFAULT_OUTPUT_FACTORY, yangPath, xmlPath, expectedNode);
161 private static void testTranslation(final XMLOutputFactory factory, final String yangPath, final String xmlPath,
162 final ContainerNode expectedNode) throws Exception {
163 final var schema = YangParserTestUtils.parseYangResource(yangPath);
164 final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream(xmlPath);
166 final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
168 final var result = new NormalizationResultHolder();
169 final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
170 final var xmlParser = XmlParserStream.create(streamWriter,
171 Inference.ofDataTreePath(schema, QName.create(MODULE, "container")));
172 xmlParser.parse(reader);
174 final var built = result.getResult().data();
175 assertNotNull(built);
177 if (expectedNode != null) {
178 assertEquals(expectedNode, built);
181 final var document = UntrustedXML.newDocumentBuilder().newDocument();
182 final var domResult = new DOMResult(document);
183 final var xmlStreamWriter = factory.createXMLStreamWriter(domResult);
184 final var xmlNormalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlStreamWriter, schema);
185 final var normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(xmlNormalizedNodeStreamWriter);
186 normalizedNodeWriter.write(built);
188 final var doc = loadDocument(xmlPath);
190 XMLUnit.setIgnoreWhitespace(true);
191 XMLUnit.setIgnoreComments(true);
192 XMLUnit.setIgnoreAttributeOrder(true);
193 XMLUnit.setNormalize(true);
195 final String expectedXml = toString(doc.getDocumentElement());
196 final String serializedXml = toString(domResult.getNode());
198 final Diff diff = new Diff(expectedXml, serializedXml);
199 diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
200 diff.overrideElementQualifier(new ElementNameAndTextQualifier());
202 // FIXME the comparison cannot be performed, since the qualifiers supplied by XMLUnit do not work correctly in
204 // We need to implement custom qualifier so that the element ordering does not mess the DIFF
205 // dd.overrideElementQualifier(new MultiLevelElementNameAndTextQualifier(100, true));
206 // assertTrue(dd.toString(), dd.similar());
208 // XMLAssert.assertXMLEqual(diff, true);
211 static List<Arguments> data() {
213 Arguments.of("/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok.xml", augmentChoiceHell()),
214 Arguments.of("/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok2.xml", null),
215 Arguments.of("/schema/augment_choice_hell.yang", "/schema/augment_choice_hell_ok3.xml",
216 augmentChoiceHell2()),
217 Arguments.of("/schema/test.yang", "/schema/simple.xml", null),
218 Arguments.of("/schema/test.yang", "/schema/simple2.xml", null),
219 // TODO check attributes
220 Arguments.of("/schema/test.yang", "/schema/simple_xml_with_attributes.xml", withAttributes()));