Realign ImmutableMapNodeBuilder and XML JSON builder
[yangtools.git] / yang / 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
9 package org.opendaylight.yangtools.yang.data.codec.xml;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.fail;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.net.URI;
19 import java.net.URISyntaxException;
20 import java.text.ParseException;
21 import java.util.HashMap;
22 import java.util.Map;
23 import javax.xml.parsers.ParserConfigurationException;
24 import javax.xml.stream.XMLInputFactory;
25 import javax.xml.stream.XMLStreamException;
26 import javax.xml.stream.XMLStreamReader;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.QNameModule;
31 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
35 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
42 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
43 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
44 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
47 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
48 import org.xml.sax.SAXException;
49
50 public class XmlToNormalizedNodesTest {
51
52     private QNameModule bazModule;
53
54     private QName outerContainer;
55
56     private QName myContainer1;
57     private QName myKeyedList;
58     private QName myKeyLeaf;
59     private QName myLeafInList1;
60     private QName myLeafInList2;
61     private QName myLeaf1;
62     private QName myLeafList;
63
64     private QName myContainer2;
65     private QName innerContainer;
66     private QName myLeaf2;
67     private QName myLeaf3;
68     private QName myChoice;
69     private QName myLeafInCase2;
70
71     private QName myContainer3;
72     private QName myDoublyKeyedList;
73     private QName myFirstKeyLeaf;
74     private QName mySecondKeyLeaf;
75     private QName myLeafInList3;
76
77     @Before
78     public void setup() throws URISyntaxException, ParseException {
79         bazModule = QNameModule.create(new URI("baz-namespace"), SimpleDateFormatUtil.getRevisionFormat().parse
80                 ("1970-01-01"));
81
82         outerContainer = QName.create(bazModule, "outer-container");
83
84         myContainer1 = QName.create(bazModule, "my-container-1");
85         myKeyedList = QName.create(bazModule, "my-keyed-list");
86         myKeyLeaf = QName.create(bazModule, "my-key-leaf");
87         myLeafInList1 = QName.create(bazModule, "my-leaf-in-list-1");
88         myLeafInList2 = QName.create(bazModule, "my-leaf-in-list-2");
89         myLeaf1 = QName.create(bazModule, "my-leaf-1");
90         myLeafList = QName.create(bazModule, "my-leaf-list");
91
92         myContainer2 = QName.create(bazModule, "my-container-2");
93         innerContainer = QName.create(bazModule, "inner-container");
94         myLeaf2 = QName.create(bazModule, "my-leaf-2");
95         myLeaf3 = QName.create(bazModule, "my-leaf-3");
96         myChoice = QName.create(bazModule, "my-choice");
97         myLeafInCase2 = QName.create(bazModule, "my-leaf-in-case-2");
98
99         myContainer3 = QName.create(bazModule, "my-container-3");
100         myDoublyKeyedList = QName.create(bazModule, "my-doubly-keyed-list");
101         myFirstKeyLeaf = QName.create(bazModule, "my-first-key-leaf");
102         mySecondKeyLeaf = QName.create(bazModule, "my-second-key-leaf");
103         myLeafInList3 = QName.create(bazModule, "my-leaf-in-list-3");
104     }
105
106     @Test
107     public void testComplexXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
108             ParserConfigurationException, SAXException {
109         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
110
111         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
112
113         final XMLInputFactory factory = XMLInputFactory.newInstance();
114         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
115
116         final NormalizedNodeResult result = new NormalizedNodeResult();
117         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
118
119         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
120         xmlParser.parse(reader);
121
122         xmlParser.flush();
123         xmlParser.close();
124
125         final NormalizedNode<?, ?> transformedInput = result.getResult();
126         assertNotNull(transformedInput);
127
128         final NormalizedNode<?, ?> expectedNormalizedNode = buildOuterContainerNode();
129         assertNotNull(expectedNormalizedNode);
130
131         assertEquals(expectedNormalizedNode, transformedInput);
132     }
133
134     @Test
135     public void testSimpleXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
136             ParserConfigurationException, SAXException {
137         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
138
139         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
140
141         final XMLInputFactory factory = XMLInputFactory.newInstance();
142         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
143
144         final NormalizedNodeResult result = new NormalizedNodeResult();
145         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
146
147         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
148         xmlParser.parse(reader);
149
150         final NormalizedNode<?, ?> transformedInput = result.getResult();
151         assertNotNull(transformedInput);
152     }
153
154     @Test
155     public void shouldFailOnDuplicateLeaf() throws ReactorException, XMLStreamException, IOException,
156             ParserConfigurationException, SAXException, URISyntaxException {
157         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
158
159         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
160
161         final XMLInputFactory factory = XMLInputFactory.newInstance();
162         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
163
164         final NormalizedNodeResult result = new NormalizedNodeResult();
165         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
166
167         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
168         try {
169             xmlParser.parse(reader);
170             fail("IllegalStateException should have been thrown because of duplicate leaf.");
171         } catch (IllegalStateException ex) {
172             assertTrue(ex.getMessage().contains("Duplicate element \"decimal64-leaf\" in XML input"));
173         }
174
175     }
176
177     @Test
178     public void shouldFailOnDuplicateAnyXml() throws ReactorException, XMLStreamException, IOException,
179             ParserConfigurationException, SAXException, URISyntaxException {
180         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
181
182         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
183
184         final XMLInputFactory factory = XMLInputFactory.newInstance();
185         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
186
187         final NormalizedNodeResult result = new NormalizedNodeResult();
188         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
189
190         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
191         try {
192             xmlParser.parse(reader);
193             fail("IllegalStateException should have been thrown because of duplicate anyxml");
194         } catch (IllegalStateException ex) {
195             assertTrue(ex.getMessage().contains("Duplicate element \"my-anyxml\" in XML input"));
196         }
197     }
198
199     @Test
200     public void shouldFailOnDuplicateContainer() throws ReactorException, XMLStreamException, IOException,
201             ParserConfigurationException, SAXException, URISyntaxException {
202         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
203
204         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
205
206         final XMLInputFactory factory = XMLInputFactory.newInstance();
207         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
208
209         final NormalizedNodeResult result = new NormalizedNodeResult();
210         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
211
212         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
213         try {
214             xmlParser.parse(reader);
215             fail("IllegalStateException should have been thrown because of duplicate container");
216         } catch (IllegalStateException ex) {
217             assertTrue(ex.getMessage().contains("Duplicate element \"leaf-container\" in XML input"));
218         }
219     }
220
221     @Test
222     public void shouldFailOnUnterminatedLeafElement() throws ReactorException, XMLStreamException, IOException,
223             ParserConfigurationException, SAXException, URISyntaxException {
224         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
225
226         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
227
228         final XMLInputFactory factory = XMLInputFactory.newInstance();
229         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
230
231         final NormalizedNodeResult result = new NormalizedNodeResult();
232         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
233
234         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
235         try {
236             xmlParser.parse(reader);
237             fail("XMLStreamException should have been thrown because of unterminated leaf element.");
238         } catch (XMLStreamException ex) {
239             assertTrue(ex.getMessage().contains("elementGetText() function expects text only elment but " +
240                     "START_ELEMENT was encountered."));
241         }
242     }
243
244     @Test
245     public void shouldFailOnUnterminatedLeafElement2() throws ReactorException, XMLStreamException, IOException,
246             ParserConfigurationException, SAXException, URISyntaxException {
247         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
248
249         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
250
251         final XMLInputFactory factory = XMLInputFactory.newInstance();
252         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
253
254         final NormalizedNodeResult result = new NormalizedNodeResult();
255         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
256
257         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
258         try {
259             xmlParser.parse(reader);
260             fail("XMLStreamException should have been thrown because of unterminated leaf element.");
261         } catch (XMLStreamException ex) {
262             assertTrue(ex.getMessage().contains("The element type \"my-leaf-1\" must be terminated by the matching " +
263                     "end-tag \"</my-leaf-1>\"."));
264         }
265     }
266
267     @Test
268     public void shouldFailOnUnterminatedContainerElement() throws ReactorException, XMLStreamException, IOException,
269             ParserConfigurationException, SAXException, URISyntaxException {
270         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
271
272         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
273
274         final XMLInputFactory factory = XMLInputFactory.newInstance();
275         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
276
277         final NormalizedNodeResult result = new NormalizedNodeResult();
278         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
279
280         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
281         try {
282             xmlParser.parse(reader);
283             fail("XMLStreamException should have been thrown because of unterminated container element.");
284         } catch (XMLStreamException ex) {
285             assertTrue(ex.getMessage().contains("The element type \"my-container-1\" must be terminated by the " +
286                     "matching end-tag \"</my-container-1>\"."));
287         }
288     }
289
290     @Test
291     public void shouldFailOnUnexistingContainerElement() throws ReactorException, XMLStreamException, IOException,
292             ParserConfigurationException, SAXException, URISyntaxException {
293         SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
294
295         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.xml");
296
297         final XMLInputFactory factory = XMLInputFactory.newInstance();
298         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
299
300         final NormalizedNodeResult result = new NormalizedNodeResult();
301         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
302
303         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
304         try {
305             xmlParser.parse(reader);
306             fail("IllegalStateException should have been thrown because of an unexisting container element.");
307         } catch (IllegalStateException ex) {
308             assertTrue(ex.getMessage().contains("Schema for node with name my-container-1 and namespace baz-namespace" +
309                     " doesn't exist."));
310         }
311     }
312
313     private NormalizedNode<?, ?> buildOuterContainerNode() {
314         // my-container-1
315         MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myKeyedList))
316                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
317                         new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue1"))
318                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
319                                 .withValue("listleafvalue1").build())
320                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
321                                 .withValue("listleafvalue2").build()).build())
322                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
323                         new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue2"))
324                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
325                                 .withValue("listleafvalue12").build())
326                         .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
327                                 .withValue("listleafvalue22").build()).build()).build();
328
329         LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf1))
330                 .withValue("value1").build();
331
332         LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(myLeafList))
333                 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
334                         new NodeWithValue<>(myLeafList, "lflvalue1")).withValue("lflvalue1").build())
335                 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
336                         new NodeWithValue<>(myLeafList, "lflvalue2")).withValue("lflvalue2").build()).build();
337
338         ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
339                 new NodeIdentifier(myContainer1))
340                 .withChild(myKeyedListNode)
341                 .withChild(myLeaf1Node)
342                 .withChild(myLeafListNode).build();
343
344         // my-container-2
345         ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
346                 new NodeIdentifier(innerContainer))
347                 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf2))
348                         .withValue("value2").build()).build();
349
350         LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf3))
351                 .withValue("value3").build();
352
353         ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(myChoice))
354                 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInCase2))
355                         .withValue("case2value").build()).build();
356
357         ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
358                 new NodeIdentifier(myContainer2))
359                 .withChild(innerContainerNode)
360                 .withChild(myLeaf3Node)
361                 .withChild(myChoiceNode).build();
362
363         // my-container-3
364         Map<QName, Object> keys = new HashMap<>();
365         keys.put(myFirstKeyLeaf, "listkeyvalue1");
366         keys.put(mySecondKeyLeaf, "listkeyvalue2");
367
368         MapNode myDoublyKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myDoublyKeyedList))
369                 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
370                         new NodeIdentifierWithPredicates(myDoublyKeyedList, keys))
371                         .withChild(Builders.leafBuilder().withNodeIdentifier(
372                                 new NodeIdentifier(myLeafInList3)).withValue("listleafvalue1").build()).build())
373                 .build();
374
375         ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
376                 new NodeIdentifier(myContainer3))
377                 .withChild(myDoublyKeyedListNode).build();
378
379         ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
380                 new NodeIdentifier(outerContainer))
381                 .withChild(myContainer1Node)
382                 .withChild(myContainer2Node)
383                 .withChild(myContainer3Node).build();
384
385         return outerContainerNode;
386     }
387 }