2f1d9fdbddb6c50e4a0a8266e6d9a27169a0d263
[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.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12
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;
42
43 @RunWith(Parameterized.class)
44 public class NormalizedNodeXmlTranslationTest extends AbstractXmlTest {
45     private final EffectiveModelContext schema;
46
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() }
57         });
58     }
59
60     private static final QNameModule MODULE = QNameModule.create(
61         XMLNamespace.of("urn:opendaylight:params:xml:ns:yang:controller:test"), Revision.of("2014-03-13"));
62
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");
69
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"))
79                         .build())
80                     .build())
81                 .build())
82             .build();
83     }
84
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))
96                         .build())
97                     .build())
98                 .build())
99             .withChild(Builders.leafBuilder()
100                 .withNodeIdentifier(getNodeIdentifier("boolean"))
101                 .withValue(Boolean.FALSE)
102                 .build())
103             .withChild(Builders.leafSetBuilder()
104                 .withNodeIdentifier(getNodeIdentifier("leafList"))
105                 .withChild(Builders.leafSetEntryBuilder()
106                     .withNodeIdentifier(new NodeWithValue<>(getNodeIdentifier("leafList").getNodeType(), "a"))
107                     .withValue("a")
108                     .build())
109                 .build())
110             .build();
111     }
112
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"))
120                     .withValue("2")
121                     .build())
122                 .withChild(Builders.choiceBuilder()
123                     .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
124                     .withChild(Builders.leafBuilder()
125                         .withNodeIdentifier(getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
126                         .withValue("2")
127                         .build())
128                     .build())
129                 .build())
130             .withChild(Builders.choiceBuilder()
131                 .withNodeIdentifier(getNodeIdentifier("ch3"))
132                 .withChild(Builders.leafBuilder()
133                     .withNodeIdentifier(getNodeIdentifier("c3Leaf"))
134                     .withValue("3")
135                     .build())
136                 .build())
137             .withChild(Builders.leafBuilder()
138                 .withNodeIdentifier(getNodeIdentifier("augLeaf"))
139                 .withValue("augment")
140                 .build())
141             .withChild(Builders.choiceBuilder()
142                 .withNodeIdentifier(getNodeIdentifier("ch"))
143                 .withChild(Builders.leafBuilder()
144                     .withNodeIdentifier(getNodeIdentifier("c1Leaf")).withValue("1")
145                     .build())
146                 .withChild(Builders.leafBuilder()
147                     .withNodeIdentifier(getNodeIdentifier("c1Leaf_AnotherAugment"))
148                     .withValue("1")
149                     .build())
150                 .withChild(Builders.choiceBuilder()
151                     .withNodeIdentifier(getNodeIdentifier("deepChoice"))
152                     .withChild(Builders.leafBuilder()
153                         .withNodeIdentifier(getNodeIdentifier("deepLeafc1"))
154                         .withValue("1")
155                         .build())
156                     .build())
157                 .build())
158             .build();
159     }
160
161     private static NodeIdentifier getNodeIdentifier(final String localName) {
162         return new NodeIdentifier(QName.create(MODULE, localName));
163     }
164
165     private final ContainerNode expectedNode;
166     private final String xmlPath;
167
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;
173     }
174
175     @Test
176     public void testTranslationRepairing() throws Exception {
177         testTranslation(TestFactories.REPAIRING_OUTPUT_FACTORY);
178     }
179
180     @Test
181     public void testTranslation() throws Exception {
182         testTranslation(TestFactories.DEFAULT_OUTPUT_FACTORY);
183     }
184
185     private void testTranslation(final XMLOutputFactory factory) throws Exception {
186         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream(xmlPath);
187
188         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
189
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);
195
196         final var built = result.getResult().data();
197         assertNotNull(built);
198
199         if (expectedNode != null) {
200             assertEquals(expectedNode, built);
201         }
202
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);
209
210         final var doc = loadDocument(xmlPath);
211
212         XMLUnit.setIgnoreWhitespace(true);
213         XMLUnit.setIgnoreComments(true);
214         XMLUnit.setIgnoreAttributeOrder(true);
215         XMLUnit.setNormalize(true);
216
217         final String expectedXml = toString(doc.getDocumentElement());
218         final String serializedXml = toString(domResult.getNode());
219
220         final Diff diff = new Diff(expectedXml, serializedXml);
221         diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener());
222         diff.overrideElementQualifier(new ElementNameAndTextQualifier());
223
224         // FIXME the comparison cannot be performed, since the qualifiers supplied by XMLUnit do not work correctly in
225         // this case
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());
229
230         // XMLAssert.assertXMLEqual(diff, true);
231     }
232 }