Convert yang-data-codec-xml to JUnit5
[yangtools.git] / codec / yang-data-codec-xml / src / test / java / org / opendaylight / yangtools / yang / data / codec / xml / NormalizedNodeXmlTranslationTest.java
1 /*
2  * Copyright (c) 2016 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.yangtools.yang.data.codec.xml;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
12
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;
40
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"));
44
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");
51
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"))
61                         .build())
62                     .build())
63                 .build())
64             .build();
65     }
66
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))
78                         .build())
79                     .build())
80                 .build())
81             .withChild(Builders.leafBuilder()
82                 .withNodeIdentifier(getNodeIdentifier("boolean"))
83                 .withValue(Boolean.FALSE)
84                 .build())
85             .withChild(Builders.leafSetBuilder()
86                 .withNodeIdentifier(getNodeIdentifier("leafList"))
87                 .withChild(Builders.leafSetEntryBuilder()
88                     .withNodeIdentifier(new NodeWithValue<>(getNodeIdentifier("leafList").getNodeType(), "a"))
89                     .withValue("a")
90                     .build())
91                 .build())
92             .build();
93     }
94
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"))
102                     .withValue("2")
103                     .build())
104                 .withChild(Builders.choiceBuilder()
105                     .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
106                     .withChild(Builders.leafBuilder()
107                         .withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
108                         .withValue("2")
109                         .build())
110                     .build())
111                 .build())
112             .withChild(Builders.choiceBuilder()
113                 .withNodeIdentifier(getNodeIdentifier("ch3"))
114                 .withChild(Builders.leafBuilder()
115                     .withNodeIdentifier(getNodeIdentifier("c3Leaf"))
116                     .withValue("3")
117                     .build())
118                 .build())
119             .withChild(Builders.leafBuilder()
120                 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
121                 .withValue("augment")
122                 .build())
123             .withChild(Builders.choiceBuilder()
124                 .withNodeIdentifier(getNodeIdentifier("ch"))
125                 .withChild(Builders.leafBuilder()
126                     .withNodeIdentifier(getNodeIdentifier("c1Leaf")).withValue("1")
127                     .build())
128                 .withChild(Builders.leafBuilder()
129                     .withNodeIdentifier(getNodeIdentifier("c1Leaf_AnotherAugment"))
130                     .withValue("1")
131                     .build())
132                 .withChild(Builders.choiceBuilder()
133                     .withNodeIdentifier(getNodeIdentifier("deepChoice"))
134                     .withChild(Builders.leafBuilder()
135                         .withNodeIdentifier(getNodeIdentifier("deepLeafc1"))
136                         .withValue("1")
137                         .build())
138                     .build())
139                 .build())
140             .build();
141     }
142
143     private static NodeIdentifier getNodeIdentifier(final String localName) {
144         return new NodeIdentifier(QName.create(MODULE, localName));
145     }
146
147     @ParameterizedTest
148     @MethodSource("data")
149     void testTranslationRepairing(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
150             throws Exception {
151         testTranslation(TestFactories.REPAIRING_OUTPUT_FACTORY, yangPath, xmlPath, expectedNode);
152     }
153
154     @ParameterizedTest
155     @MethodSource("data")
156     void testTranslation(final String yangPath, final String xmlPath, final ContainerNode expectedNode)
157             throws Exception {
158         testTranslation(TestFactories.DEFAULT_OUTPUT_FACTORY, yangPath, xmlPath, expectedNode);
159     }
160
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);
165
166         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
167
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);
173
174         final var built = result.getResult().data();
175         assertNotNull(built);
176
177         if (expectedNode != null) {
178             assertEquals(expectedNode, built);
179         }
180
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);
187
188         final var doc = loadDocument(xmlPath);
189
190         XMLUnit.setIgnoreWhitespace(true);
191         XMLUnit.setIgnoreComments(true);
192         XMLUnit.setIgnoreAttributeOrder(true);
193         XMLUnit.setNormalize(true);
194
195         final String expectedXml = toString(doc.getDocumentElement());
196         final String serializedXml = toString(domResult.getNode());
197
198         final Diff diff = new Diff(expectedXml, serializedXml);
199         diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
200         diff.overrideElementQualifier(new ElementNameAndTextQualifier());
201
202         // FIXME the comparison cannot be performed, since the qualifiers supplied by XMLUnit do not work correctly in
203         // this case
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());
207
208         // XMLAssert.assertXMLEqual(diff, true);
209     }
210
211     static List<Arguments> data() {
212         return List.of(
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()));
221     }
222 }