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
9 package org.opendaylight.yangtools.yang.data.codec.xml;
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;
16 import com.google.common.collect.Sets;
17 import java.io.IOException;
18 import java.io.InputStream;
20 import java.net.URISyntaxException;
21 import java.text.ParseException;
22 import java.util.HashMap;
24 import javax.xml.parsers.ParserConfigurationException;
25 import javax.xml.stream.XMLInputFactory;
26 import javax.xml.stream.XMLStreamException;
27 import javax.xml.stream.XMLStreamReader;
28 import org.junit.Before;
29 import org.junit.Test;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.common.QNameModule;
32 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
37 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
45 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
46 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
47 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
50 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
51 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
52 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
53 import org.xml.sax.SAXException;
55 public class XmlToNormalizedNodesTest {
57 private QNameModule bazModule;
59 private QName outerContainer;
61 private QName myContainer1;
62 private QName myKeyedList;
63 private QName myKeyLeaf;
64 private QName myLeafInList1;
65 private QName myLeafInList2;
66 private QName myLeaf1;
67 private QName myLeafList;
69 private QName myContainer2;
70 private QName innerContainer;
71 private QName myLeaf2;
72 private QName myLeaf3;
73 private QName myChoice;
74 private QName myLeafInCase2;
76 private QName myContainer3;
77 private QName myDoublyKeyedList;
78 private QName myFirstKeyLeaf;
79 private QName mySecondKeyLeaf;
80 private QName myLeafInList3;
83 public void setup() throws URISyntaxException, ParseException {
84 bazModule = QNameModule.create(new URI("baz-namespace"), SimpleDateFormatUtil.getRevisionFormat().parse
87 outerContainer = QName.create(bazModule, "outer-container");
89 myContainer1 = QName.create(bazModule, "my-container-1");
90 myKeyedList = QName.create(bazModule, "my-keyed-list");
91 myKeyLeaf = QName.create(bazModule, "my-key-leaf");
92 myLeafInList1 = QName.create(bazModule, "my-leaf-in-list-1");
93 myLeafInList2 = QName.create(bazModule, "my-leaf-in-list-2");
94 myLeaf1 = QName.create(bazModule, "my-leaf-1");
95 myLeafList = QName.create(bazModule, "my-leaf-list");
97 myContainer2 = QName.create(bazModule, "my-container-2");
98 innerContainer = QName.create(bazModule, "inner-container");
99 myLeaf2 = QName.create(bazModule, "my-leaf-2");
100 myLeaf3 = QName.create(bazModule, "my-leaf-3");
101 myChoice = QName.create(bazModule, "my-choice");
102 myLeafInCase2 = QName.create(bazModule, "my-leaf-in-case-2");
104 myContainer3 = QName.create(bazModule, "my-container-3");
105 myDoublyKeyedList = QName.create(bazModule, "my-doubly-keyed-list");
106 myFirstKeyLeaf = QName.create(bazModule, "my-first-key-leaf");
107 mySecondKeyLeaf = QName.create(bazModule, "my-second-key-leaf");
108 myLeafInList3 = QName.create(bazModule, "my-leaf-in-list-3");
112 public void testComplexXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
113 ParserConfigurationException, SAXException {
114 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
115 reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
117 SchemaContext schemaContext = reactor.buildEffective();
119 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
121 final XMLInputFactory factory = XMLInputFactory.newInstance();
122 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
124 final NormalizedNodeResult result = new NormalizedNodeResult();
125 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
127 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
128 xmlParser.parse(reader);
130 final NormalizedNode<?, ?> transformedInput = result.getResult();
131 assertNotNull(transformedInput);
133 final NormalizedNode<?, ?> expectedNormalizedNode = buildOuterContainerNode();
134 assertNotNull(expectedNormalizedNode);
136 assertEquals(expectedNormalizedNode, transformedInput);
140 public void testSimpleXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
141 ParserConfigurationException, SAXException {
142 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
143 reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
145 SchemaContext schemaContext = reactor.buildEffective();
147 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
149 final XMLInputFactory factory = XMLInputFactory.newInstance();
150 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
152 final NormalizedNodeResult result = new NormalizedNodeResult();
153 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
155 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
156 xmlParser.parse(reader);
158 final NormalizedNode<?, ?> transformedInput = result.getResult();
159 assertNotNull(transformedInput);
163 public void shouldFailOnDuplicateLeaf() throws ReactorException, XMLStreamException, IOException,
164 ParserConfigurationException, SAXException, URISyntaxException {
165 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
166 reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
168 SchemaContext schemaContext = reactor.buildEffective();
170 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
172 final XMLInputFactory factory = XMLInputFactory.newInstance();
173 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
175 final NormalizedNodeResult result = new NormalizedNodeResult();
176 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
178 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
180 xmlParser.parse(reader);
181 fail("IllegalStateException should have been thrown because of duplicate leaf.");
182 } catch (IllegalStateException ex) {
183 assertTrue(ex.getMessage().contains("Duplicate element \"decimal64-leaf\" in XML input"));
189 public void shouldFailOnDuplicateAnyXml() throws ReactorException, XMLStreamException, IOException,
190 ParserConfigurationException, SAXException, URISyntaxException {
191 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
192 reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
194 SchemaContext schemaContext = reactor.buildEffective();
196 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
198 final XMLInputFactory factory = XMLInputFactory.newInstance();
199 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
201 final NormalizedNodeResult result = new NormalizedNodeResult();
202 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
204 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
206 xmlParser.parse(reader);
207 fail("IllegalStateException should have been thrown because of duplicate anyxml");
208 } catch (IllegalStateException ex) {
209 assertTrue(ex.getMessage().contains("Duplicate element \"my-anyxml\" in XML input"));
214 public void shouldFailOnDuplicateContainer() throws ReactorException, XMLStreamException, IOException,
215 ParserConfigurationException, SAXException, URISyntaxException {
216 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
217 reactor.addSource(new YangStatementSourceImpl("/foo.yang", false));
219 SchemaContext schemaContext = reactor.buildEffective();
221 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
223 final XMLInputFactory factory = XMLInputFactory.newInstance();
224 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
226 final NormalizedNodeResult result = new NormalizedNodeResult();
227 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
229 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
231 xmlParser.parse(reader);
232 fail("IllegalStateException should have been thrown because of duplicate container");
233 } catch (IllegalStateException ex) {
234 assertTrue(ex.getMessage().contains("Duplicate element \"leaf-container\" in XML input"));
239 public void shouldFailOnUnterminatedLeafElement() throws ReactorException, XMLStreamException, IOException,
240 ParserConfigurationException, SAXException, URISyntaxException {
241 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
242 reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
244 SchemaContext schemaContext = reactor.buildEffective();
246 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
248 final XMLInputFactory factory = XMLInputFactory.newInstance();
249 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
251 final NormalizedNodeResult result = new NormalizedNodeResult();
252 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
254 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
256 xmlParser.parse(reader);
257 fail("XMLStreamException should have been thrown because of unterminated leaf element.");
258 } catch (XMLStreamException ex) {
259 assertTrue(ex.getMessage().contains("elementGetText() function expects text only elment but " +
260 "START_ELEMENT was encountered."));
265 public void shouldFailOnUnterminatedLeafElement2() throws ReactorException, XMLStreamException, IOException,
266 ParserConfigurationException, SAXException, URISyntaxException {
267 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
268 reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
270 SchemaContext schemaContext = reactor.buildEffective();
272 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
274 final XMLInputFactory factory = XMLInputFactory.newInstance();
275 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
277 final NormalizedNodeResult result = new NormalizedNodeResult();
278 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
280 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
282 xmlParser.parse(reader);
283 fail("XMLStreamException should have been thrown because of unterminated leaf element.");
284 } catch (XMLStreamException ex) {
285 assertTrue(ex.getMessage().contains("The element type \"my-leaf-1\" must be terminated by the matching " +
286 "end-tag \"</my-leaf-1>\"."));
291 public void shouldFailOnUnterminatedContainerElement() throws ReactorException, XMLStreamException, IOException,
292 ParserConfigurationException, SAXException, URISyntaxException {
293 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
294 reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
296 SchemaContext schemaContext = reactor.buildEffective();
298 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
300 final XMLInputFactory factory = XMLInputFactory.newInstance();
301 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
303 final NormalizedNodeResult result = new NormalizedNodeResult();
304 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
306 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
308 xmlParser.parse(reader);
309 fail("XMLStreamException should have been thrown because of unterminated container element.");
310 } catch (XMLStreamException ex) {
311 assertTrue(ex.getMessage().contains("The element type \"my-container-1\" must be terminated by the " +
312 "matching end-tag \"</my-container-1>\"."));
317 public void shouldFailOnUnexistingContainerElement() throws ReactorException, XMLStreamException, IOException,
318 ParserConfigurationException, SAXException, URISyntaxException {
319 CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
320 reactor.addSource(new YangStatementSourceImpl("/baz.yang", false));
322 SchemaContext schemaContext = reactor.buildEffective();
324 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.xml");
326 final XMLInputFactory factory = XMLInputFactory.newInstance();
327 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
329 final NormalizedNodeResult result = new NormalizedNodeResult();
330 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
332 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
334 xmlParser.parse(reader);
335 fail("IllegalStateException should have been thrown because of an unexisting container element.");
336 } catch (IllegalStateException ex) {
337 assertTrue(ex.getMessage().contains("Schema for node with name my-container-1 and namespace baz-namespace" +
342 private NormalizedNode<?, ?> buildOuterContainerNode() {
344 MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myKeyedList))
345 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
346 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue1"))
347 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
348 .withValue("listleafvalue1").build())
349 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
350 .withValue("listleafvalue2").build()).build())
351 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
352 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue2"))
353 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
354 .withValue("listleafvalue12").build())
355 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
356 .withValue("listleafvalue22").build()).build()).build();
358 LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf1))
359 .withValue("value1").build();
361 LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(myLeafList))
362 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
363 new NodeWithValue<>(myLeafList, "lflvalue1")).withValue("lflvalue1").build())
364 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
365 new NodeWithValue<>(myLeafList, "lflvalue2")).withValue("lflvalue2").build()).build();
367 ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
368 new NodeIdentifier(myContainer1))
369 .withChild(myKeyedListNode)
370 .withChild(myLeaf1Node)
371 .withChild(myLeafListNode).build();
374 ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
375 new NodeIdentifier(innerContainer))
376 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf2))
377 .withValue("value2").build()).build();
379 LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf3))
380 .withValue("value3").build();
382 ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(myChoice))
383 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInCase2))
384 .withValue("case2value").build()).build();
386 ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
387 new NodeIdentifier(myContainer2))
388 .withChild(innerContainerNode)
389 .withChild(myLeaf3Node)
390 .withChild(myChoiceNode).build();
393 Map<QName, Object> keys = new HashMap<>();
394 keys.put(myFirstKeyLeaf, "listkeyvalue1");
395 keys.put(mySecondKeyLeaf, "listkeyvalue2");
397 MapNode myDoublyKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myDoublyKeyedList))
398 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
399 new NodeIdentifierWithPredicates(myDoublyKeyedList, keys))
400 .withChild(Builders.leafBuilder().withNodeIdentifier(
401 new NodeIdentifier(myLeafInList3)).withValue("listleafvalue1").build()).build())
404 AugmentationNode myDoublyKeyedListAugNode = Builders.augmentationBuilder().withNodeIdentifier(
405 new AugmentationIdentifier(Sets.newHashSet(myDoublyKeyedList)))
406 .withChild(myDoublyKeyedListNode).build();
408 ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
409 new NodeIdentifier(myContainer3))
410 .withChild(myDoublyKeyedListAugNode).build();
412 AugmentationNode myContainer3AugNode = Builders.augmentationBuilder().withNodeIdentifier(
413 new AugmentationIdentifier(Sets.newHashSet(myContainer3)))
414 .withChild(myContainer3Node).build();
416 ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
417 new NodeIdentifier(outerContainer))
418 .withChild(myContainer1Node)
419 .withChild(myContainer2Node)
420 .withChild(myContainer3AugNode).build();
422 return outerContainerNode;