Migrate users of deprecated QNameModule methods
[yangtools.git] / codec / yang-data-codec-xml / src / test / java / org / opendaylight / yangtools / yang / data / codec / xml / XmlToNormalizedNodesTest.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.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.jupiter.api.Assertions.assertEquals;
13 import static org.junit.jupiter.api.Assertions.assertNotNull;
14 import static org.junit.jupiter.api.Assertions.assertThrows;
15
16 import java.io.IOException;
17 import java.net.URISyntaxException;
18 import java.util.HashMap;
19 import java.util.Map;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.stream.XMLStreamException;
22 import org.junit.jupiter.api.AfterAll;
23 import org.junit.jupiter.api.BeforeAll;
24 import org.junit.jupiter.api.Test;
25 import org.opendaylight.yangtools.util.xml.UntrustedXML;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.QNameModule;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
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.data.spi.node.ImmutableNodes;
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 import org.xml.sax.SAXException;
43
44 class XmlToNormalizedNodesTest {
45     private static final QName PARENT_CONTAINER = QName.create("foo-namespace", "parent-container");
46
47     private static final QNameModule BAZ_MODULE = QNameModule.of("baz-namespace");
48     private static final QName OUTER_CONTAINER = QName.create(BAZ_MODULE, "outer-container");
49
50     private static final QName MY_CONTAINER_1 = QName.create(BAZ_MODULE, "my-container-1");
51     private static final QName MY_KEYED_LIST = QName.create(BAZ_MODULE, "my-keyed-list");
52     private static final QName MY_KEY_LEAF = QName.create(BAZ_MODULE, "my-key-leaf");
53     private static final QName MY_LEAF_IN_LIST_1 = QName.create(BAZ_MODULE, "my-leaf-in-list-1");
54     private static final QName MY_LEAF_IN_LIST_2 = QName.create(BAZ_MODULE, "my-leaf-in-list-2");
55     private static final QName MY_LEAF_1 = QName.create(BAZ_MODULE, "my-leaf-1");
56     private static final QName MY_LEAFLIST = QName.create(BAZ_MODULE, "my-leaf-list");
57
58     private static final QName MY_CONTAINER_2 = QName.create(BAZ_MODULE, "my-container-2");
59     private static final QName INNER_CONTAINER = QName.create(BAZ_MODULE, "inner-container");
60     private static final QName MY_LEAF_2 = QName.create(BAZ_MODULE, "my-leaf-2");
61     private static final QName MY_LEAF_3 = QName.create(BAZ_MODULE, "my-leaf-3");
62     private static final QName MY_CHOICE = QName.create(BAZ_MODULE, "my-choice");
63     private static final QName MY_LEAF_IN_CASE_2 = QName.create(BAZ_MODULE, "my-leaf-in-case-2");
64
65     private static final QName MY_CONTAINER_3 = QName.create(BAZ_MODULE, "my-container-3");
66     private static final QName MY_DOUBLY_KEYED_LIST = QName.create(BAZ_MODULE, "my-doubly-keyed-list");
67     private static final QName MY_FIRST_KEY_LEAF = QName.create(BAZ_MODULE, "my-first-key-leaf");
68     private static final QName MY_SECOND_KEY_LEAF = QName.create(BAZ_MODULE, "my-second-key-leaf");
69     private static final QName MY_LEAF_IN_LIST_3 = QName.create(BAZ_MODULE, "my-leaf-in-list-3");
70
71     private static EffectiveModelContext schemaContext;
72     private static Inference outerContainerSchema;
73     private static Inference parentContainerSchema;
74
75     @BeforeAll
76     static void setup() {
77         schemaContext = YangParserTestUtils.parseYangResources(XmlToNormalizedNodesTest.class,
78             "/foo.yang", "/baz.yang");
79         parentContainerSchema = Inference.ofDataTreePath(schemaContext, PARENT_CONTAINER);
80         outerContainerSchema = Inference.ofDataTreePath(schemaContext, OUTER_CONTAINER);
81     }
82
83     @AfterAll
84     static void cleanup() {
85         schemaContext = null;
86         parentContainerSchema = null;
87         outerContainerSchema = null;
88     }
89
90     @Test
91     void testComplexXmlParsing() throws IOException, SAXException, URISyntaxException, XMLStreamException,
92             ParserConfigurationException {
93         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
94         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
95         final var result = new NormalizationResultHolder();
96         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
97
98         try (var xmlParser = XmlParserStream.create(streamWriter, outerContainerSchema)) {
99             xmlParser.parse(reader);
100         }
101
102         final NormalizedNode transformedInput = result.getResult().data();
103         assertNotNull(transformedInput);
104
105         final NormalizedNode expectedNormalizedNode = buildOuterContainerNode();
106         assertNotNull(expectedNormalizedNode);
107
108         assertEquals(expectedNormalizedNode, transformedInput);
109     }
110
111     @Test
112     void testSimpleXmlParsing() throws IOException, URISyntaxException, XMLStreamException,
113             ParserConfigurationException, SAXException {
114         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
115         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
116         final var result = new NormalizationResultHolder();
117         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
118         final var xmlParser = XmlParserStream.create(streamWriter, parentContainerSchema);
119         xmlParser.parse(reader);
120
121         final var transformedInput = result.getResult().data();
122         assertNotNull(transformedInput);
123     }
124
125     @Test
126     void shouldFailOnDuplicateLeaf() throws XMLStreamException, IOException,
127             ParserConfigurationException, SAXException, URISyntaxException {
128         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
129         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
130         final var result = new NormalizationResultHolder();
131         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
132         final var xmlParser = XmlParserStream.create(streamWriter, parentContainerSchema);
133         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
134         assertThat(ex.getMessage(), containsString("""
135             Duplicate element "decimal64-leaf" in namespace "foo-namespace" with parent \
136             "EmptyContainerEffectiveStatement{argument=(foo-namespace)leaf-container}" in XML input"""));
137     }
138
139     @Test
140     void shouldFailOnDuplicateAnyXml() throws XMLStreamException, IOException,
141             ParserConfigurationException, SAXException, URISyntaxException {
142         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
143         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
144         final var result = new NormalizationResultHolder();
145         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
146         final var xmlParser = XmlParserStream.create(streamWriter, parentContainerSchema);
147         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
148         assertThat(ex.getMessage(), containsString("""
149             Duplicate element "my-anyxml" in namespace "foo-namespace" with parent \
150             "EmptyContainerEffectiveStatement{argument=(foo-namespace)anyxml-container}" in XML input"""));
151     }
152
153     @Test
154     void shouldFailOnDuplicateContainer() throws XMLStreamException, IOException,
155             ParserConfigurationException, SAXException, URISyntaxException {
156         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
157         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
158         final var result = new NormalizationResultHolder();
159         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
160         final var xmlParser = XmlParserStream.create(streamWriter, parentContainerSchema);
161         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
162         assertThat(ex.getMessage(), containsString("""
163             Duplicate element "leaf-container" in namespace "foo-namespace" with parent \
164             "EmptyContainerEffectiveStatement{argument=(foo-namespace)parent-container}" in XML input"""));
165     }
166
167     @Test
168     void shouldFailOnUnterminatedLeafElement() throws XMLStreamException, IOException,
169             ParserConfigurationException, SAXException, URISyntaxException {
170         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
171         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
172         final var result = new NormalizationResultHolder();
173         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
174         final var xmlParser = XmlParserStream.create(streamWriter, outerContainerSchema);
175         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
176         assertThat(ex.getMessage(), containsString(" START_ELEMENT "));
177     }
178
179     @Test
180     void shouldFailOnUnterminatedLeafElement2() throws XMLStreamException, IOException,
181             ParserConfigurationException, SAXException, URISyntaxException {
182         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
183         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
184         final var result = new NormalizationResultHolder();
185         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
186         final var xmlParser = XmlParserStream.create(streamWriter, outerContainerSchema);
187         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
188         assertThat(ex.getMessage(), containsString("</my-leaf-1>"));
189     }
190
191     @Test
192     void shouldFailOnUnterminatedContainerElement() throws XMLStreamException, IOException,
193             ParserConfigurationException, SAXException, URISyntaxException {
194         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
195         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
196         final var result = new NormalizationResultHolder();
197         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
198         final var xmlParser = XmlParserStream.create(streamWriter, outerContainerSchema);
199         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
200         assertThat(ex.getMessage(), containsString("</my-container-1>"));
201     }
202
203     @Test
204     void shouldFailOnUnknownChildNode() throws XMLStreamException, IOException,
205             ParserConfigurationException, SAXException, URISyntaxException {
206         final var resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.xml");
207         final var reader = UntrustedXML.createXMLStreamReader(resourceAsStream);
208         final var result = new NormalizationResultHolder();
209         final var streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
210         final var xmlParser = XmlParserStream.create(streamWriter, outerContainerSchema);
211         final var ex = assertThrows(XMLStreamException.class, () -> xmlParser.parse(reader));
212         assertThat(ex.getMessage(), containsString("""
213             Schema for node with name my-container-1 and namespace baz-namespace does not exist in parent \
214             EmptyContainerEffectiveStatement{argument=(baz-namespace)my-container-1}"""));
215     }
216
217     private static NormalizedNode buildOuterContainerNode() {
218         // my-container-1
219         MapNode myKeyedListNode = ImmutableNodes.newSystemMapBuilder()
220             .withNodeIdentifier(new NodeIdentifier(MY_KEYED_LIST))
221             .withChild(ImmutableNodes.newMapEntryBuilder()
222                 .withNodeIdentifier(NodeIdentifierWithPredicates.of(MY_KEYED_LIST, MY_KEY_LEAF, "listkeyvalue1"))
223                 .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_LIST_1, "listleafvalue1"))
224                 .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_LIST_2, "listleafvalue2"))
225                 .build())
226             .withChild(ImmutableNodes.newMapEntryBuilder().withNodeIdentifier(
227                 NodeIdentifierWithPredicates.of(MY_KEYED_LIST, MY_KEY_LEAF, "listkeyvalue2"))
228                 .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_LIST_1, "listleafvalue12"))
229                 .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_LIST_2, "listleafvalue22"))
230                 .build())
231             .build();
232
233         LeafNode<?> myLeaf1Node = ImmutableNodes.leafNode(MY_LEAF_1, "value1");
234
235         SystemLeafSetNode<?> myLeafListNode = ImmutableNodes.newSystemLeafSetBuilder()
236             .withNodeIdentifier(new NodeIdentifier(MY_LEAFLIST))
237             .withChild(ImmutableNodes.leafSetEntry(MY_LEAFLIST, "lflvalue1"))
238             .withChild(ImmutableNodes.leafSetEntry(MY_LEAFLIST, "lflvalue2"))
239             .build();
240
241         ContainerNode myContainer1Node = ImmutableNodes.newContainerBuilder()
242             .withNodeIdentifier(new NodeIdentifier(MY_CONTAINER_1))
243             .withChild(myKeyedListNode)
244             .withChild(myLeaf1Node)
245             .withChild(myLeafListNode)
246             .build();
247
248         // my-container-2
249         ContainerNode innerContainerNode = ImmutableNodes.newContainerBuilder()
250             .withNodeIdentifier(new NodeIdentifier(INNER_CONTAINER))
251             .withChild(ImmutableNodes.leafNode(MY_LEAF_2, "value2"))
252             .build();
253
254         LeafNode<?> myLeaf3Node = ImmutableNodes.leafNode(MY_LEAF_3, "value3");
255
256         ChoiceNode myChoiceNode = ImmutableNodes.newChoiceBuilder()
257             .withNodeIdentifier(new NodeIdentifier(MY_CHOICE))
258             .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_CASE_2, "case2value"))
259             .build();
260
261         ContainerNode myContainer2Node = ImmutableNodes.newContainerBuilder()
262             .withNodeIdentifier(new NodeIdentifier(MY_CONTAINER_2))
263             .withChild(innerContainerNode)
264             .withChild(myLeaf3Node)
265             .withChild(myChoiceNode)
266             .build();
267
268         // my-container-3
269         Map<QName, Object> keys = new HashMap<>();
270         keys.put(MY_FIRST_KEY_LEAF, "listkeyvalue1");
271         keys.put(MY_SECOND_KEY_LEAF, "listkeyvalue2");
272
273         MapNode myDoublyKeyedListNode = ImmutableNodes.newSystemMapBuilder()
274                 .withNodeIdentifier(new NodeIdentifier(MY_DOUBLY_KEYED_LIST))
275                 .withChild(ImmutableNodes.newMapEntryBuilder()
276                     .withNodeIdentifier(NodeIdentifierWithPredicates.of(MY_DOUBLY_KEYED_LIST, keys))
277                     .withChild(ImmutableNodes.leafNode(MY_LEAF_IN_LIST_3, "listleafvalue1"))
278                     .build())
279                 .build();
280
281         ContainerNode myContainer3Node = ImmutableNodes.newContainerBuilder()
282             .withNodeIdentifier(new NodeIdentifier(MY_CONTAINER_3))
283             .withChild(myDoublyKeyedListNode)
284             .build();
285
286         ContainerNode outerContainerNode = ImmutableNodes.newContainerBuilder()
287             .withNodeIdentifier(new NodeIdentifier(OUTER_CONTAINER))
288             .withChild(myContainer1Node)
289             .withChild(myContainer2Node)
290             .withChild(myContainer3Node)
291             .build();
292
293         return outerContainerNode;
294     }
295 }