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.test.util.YangParserTestUtils;
51 import org.xml.sax.SAXException;
53 public class XmlToNormalizedNodesTest {
55 private QNameModule bazModule;
57 private QName outerContainer;
59 private QName myContainer1;
60 private QName myKeyedList;
61 private QName myKeyLeaf;
62 private QName myLeafInList1;
63 private QName myLeafInList2;
64 private QName myLeaf1;
65 private QName myLeafList;
67 private QName myContainer2;
68 private QName innerContainer;
69 private QName myLeaf2;
70 private QName myLeaf3;
71 private QName myChoice;
72 private QName myLeafInCase2;
74 private QName myContainer3;
75 private QName myDoublyKeyedList;
76 private QName myFirstKeyLeaf;
77 private QName mySecondKeyLeaf;
78 private QName myLeafInList3;
81 public void setup() throws URISyntaxException, ParseException {
82 bazModule = QNameModule.create(new URI("baz-namespace"), SimpleDateFormatUtil.getRevisionFormat().parse
85 outerContainer = QName.create(bazModule, "outer-container");
87 myContainer1 = QName.create(bazModule, "my-container-1");
88 myKeyedList = QName.create(bazModule, "my-keyed-list");
89 myKeyLeaf = QName.create(bazModule, "my-key-leaf");
90 myLeafInList1 = QName.create(bazModule, "my-leaf-in-list-1");
91 myLeafInList2 = QName.create(bazModule, "my-leaf-in-list-2");
92 myLeaf1 = QName.create(bazModule, "my-leaf-1");
93 myLeafList = QName.create(bazModule, "my-leaf-list");
95 myContainer2 = QName.create(bazModule, "my-container-2");
96 innerContainer = QName.create(bazModule, "inner-container");
97 myLeaf2 = QName.create(bazModule, "my-leaf-2");
98 myLeaf3 = QName.create(bazModule, "my-leaf-3");
99 myChoice = QName.create(bazModule, "my-choice");
100 myLeafInCase2 = QName.create(bazModule, "my-leaf-in-case-2");
102 myContainer3 = QName.create(bazModule, "my-container-3");
103 myDoublyKeyedList = QName.create(bazModule, "my-doubly-keyed-list");
104 myFirstKeyLeaf = QName.create(bazModule, "my-first-key-leaf");
105 mySecondKeyLeaf = QName.create(bazModule, "my-second-key-leaf");
106 myLeafInList3 = QName.create(bazModule, "my-leaf-in-list-3");
110 public void testComplexXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
111 ParserConfigurationException, SAXException {
112 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
114 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/baz.xml");
116 final XMLInputFactory factory = XMLInputFactory.newInstance();
117 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
119 final NormalizedNodeResult result = new NormalizedNodeResult();
120 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
122 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
123 xmlParser.parse(reader);
128 final NormalizedNode<?, ?> transformedInput = result.getResult();
129 assertNotNull(transformedInput);
131 final NormalizedNode<?, ?> expectedNormalizedNode = buildOuterContainerNode();
132 assertNotNull(expectedNormalizedNode);
134 assertEquals(expectedNormalizedNode, transformedInput);
138 public void testSimpleXmlParsing() throws IOException, URISyntaxException, ReactorException, XMLStreamException,
139 ParserConfigurationException, SAXException {
140 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
142 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/foo.xml");
144 final XMLInputFactory factory = XMLInputFactory.newInstance();
145 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
147 final NormalizedNodeResult result = new NormalizedNodeResult();
148 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
150 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
151 xmlParser.parse(reader);
153 final NormalizedNode<?, ?> transformedInput = result.getResult();
154 assertNotNull(transformedInput);
158 public void shouldFailOnDuplicateLeaf() throws ReactorException, XMLStreamException, IOException,
159 ParserConfigurationException, SAXException, URISyntaxException {
160 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
162 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo.xml");
164 final XMLInputFactory factory = XMLInputFactory.newInstance();
165 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
167 final NormalizedNodeResult result = new NormalizedNodeResult();
168 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
170 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
172 xmlParser.parse(reader);
173 fail("IllegalStateException should have been thrown because of duplicate leaf.");
174 } catch (IllegalStateException ex) {
175 assertTrue(ex.getMessage().contains("Duplicate element \"decimal64-leaf\" in XML input"));
181 public void shouldFailOnDuplicateAnyXml() throws ReactorException, XMLStreamException, IOException,
182 ParserConfigurationException, SAXException, URISyntaxException {
183 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
185 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-2.xml");
187 final XMLInputFactory factory = XMLInputFactory.newInstance();
188 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
190 final NormalizedNodeResult result = new NormalizedNodeResult();
191 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
193 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
195 xmlParser.parse(reader);
196 fail("IllegalStateException should have been thrown because of duplicate anyxml");
197 } catch (IllegalStateException ex) {
198 assertTrue(ex.getMessage().contains("Duplicate element \"my-anyxml\" in XML input"));
203 public void shouldFailOnDuplicateContainer() throws ReactorException, XMLStreamException, IOException,
204 ParserConfigurationException, SAXException, URISyntaxException {
205 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/foo.yang");
207 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-foo-3.xml");
209 final XMLInputFactory factory = XMLInputFactory.newInstance();
210 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
212 final NormalizedNodeResult result = new NormalizedNodeResult();
213 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
215 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
217 xmlParser.parse(reader);
218 fail("IllegalStateException should have been thrown because of duplicate container");
219 } catch (IllegalStateException ex) {
220 assertTrue(ex.getMessage().contains("Duplicate element \"leaf-container\" in XML input"));
225 public void shouldFailOnUnterminatedLeafElement() throws ReactorException, XMLStreamException, IOException,
226 ParserConfigurationException, SAXException, URISyntaxException {
227 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
229 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz.xml");
231 final XMLInputFactory factory = XMLInputFactory.newInstance();
232 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
234 final NormalizedNodeResult result = new NormalizedNodeResult();
235 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
237 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
239 xmlParser.parse(reader);
240 fail("XMLStreamException should have been thrown because of unterminated leaf element.");
241 } catch (XMLStreamException ex) {
242 assertTrue(ex.getMessage().contains("elementGetText() function expects text only elment but " +
243 "START_ELEMENT was encountered."));
248 public void shouldFailOnUnterminatedLeafElement2() throws ReactorException, XMLStreamException, IOException,
249 ParserConfigurationException, SAXException, URISyntaxException {
250 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
252 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-2.xml");
254 final XMLInputFactory factory = XMLInputFactory.newInstance();
255 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
257 final NormalizedNodeResult result = new NormalizedNodeResult();
258 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
260 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
262 xmlParser.parse(reader);
263 fail("XMLStreamException should have been thrown because of unterminated leaf element.");
264 } catch (XMLStreamException ex) {
265 assertTrue(ex.getMessage().contains("The element type \"my-leaf-1\" must be terminated by the matching " +
266 "end-tag \"</my-leaf-1>\"."));
271 public void shouldFailOnUnterminatedContainerElement() throws ReactorException, XMLStreamException, IOException,
272 ParserConfigurationException, SAXException, URISyntaxException {
273 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
275 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-4.xml");
277 final XMLInputFactory factory = XMLInputFactory.newInstance();
278 final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
280 final NormalizedNodeResult result = new NormalizedNodeResult();
281 final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
283 final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext, schemaContext);
285 xmlParser.parse(reader);
286 fail("XMLStreamException should have been thrown because of unterminated container element.");
287 } catch (XMLStreamException ex) {
288 assertTrue(ex.getMessage().contains("The element type \"my-container-1\" must be terminated by the " +
289 "matching end-tag \"</my-container-1>\"."));
294 public void shouldFailOnUnexistingContainerElement() throws ReactorException, XMLStreamException, IOException,
295 ParserConfigurationException, SAXException, URISyntaxException {
296 SchemaContext schemaContext = YangParserTestUtils.parseYangSource("/baz.yang");
298 final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/invalid-baz-3.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, schemaContext);
308 xmlParser.parse(reader);
309 fail("IllegalStateException should have been thrown because of an unexisting container element.");
310 } catch (IllegalStateException ex) {
311 assertTrue(ex.getMessage().contains("Schema for node with name my-container-1 and namespace baz-namespace" +
316 private NormalizedNode<?, ?> buildOuterContainerNode() {
318 MapNode myKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myKeyedList))
319 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
320 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue1"))
321 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
322 .withValue("listleafvalue1").build())
323 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
324 .withValue("listleafvalue2").build()).build())
325 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
326 new NodeIdentifierWithPredicates(myKeyedList, myKeyLeaf, "listkeyvalue2"))
327 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList1))
328 .withValue("listleafvalue12").build())
329 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInList2))
330 .withValue("listleafvalue22").build()).build()).build();
332 LeafNode<?> myLeaf1Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf1))
333 .withValue("value1").build();
335 LeafSetNode<?> myLeafListNode = Builders.leafSetBuilder().withNodeIdentifier(new NodeIdentifier(myLeafList))
336 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
337 new NodeWithValue<>(myLeafList, "lflvalue1")).withValue("lflvalue1").build())
338 .withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(
339 new NodeWithValue<>(myLeafList, "lflvalue2")).withValue("lflvalue2").build()).build();
341 ContainerNode myContainer1Node = Builders.containerBuilder().withNodeIdentifier(
342 new NodeIdentifier(myContainer1))
343 .withChild(myKeyedListNode)
344 .withChild(myLeaf1Node)
345 .withChild(myLeafListNode).build();
348 ContainerNode innerContainerNode = Builders.containerBuilder().withNodeIdentifier(
349 new NodeIdentifier(innerContainer))
350 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf2))
351 .withValue("value2").build()).build();
353 LeafNode<?> myLeaf3Node = Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeaf3))
354 .withValue("value3").build();
356 ChoiceNode myChoiceNode = Builders.choiceBuilder().withNodeIdentifier(new NodeIdentifier(myChoice))
357 .withChild(Builders.leafBuilder().withNodeIdentifier(new NodeIdentifier(myLeafInCase2))
358 .withValue("case2value").build()).build();
360 ContainerNode myContainer2Node = Builders.containerBuilder().withNodeIdentifier(
361 new NodeIdentifier(myContainer2))
362 .withChild(innerContainerNode)
363 .withChild(myLeaf3Node)
364 .withChild(myChoiceNode).build();
367 Map<QName, Object> keys = new HashMap<>();
368 keys.put(myFirstKeyLeaf, "listkeyvalue1");
369 keys.put(mySecondKeyLeaf, "listkeyvalue2");
371 MapNode myDoublyKeyedListNode = Builders.mapBuilder().withNodeIdentifier(new NodeIdentifier(myDoublyKeyedList))
372 .withChild(Builders.mapEntryBuilder().withNodeIdentifier(
373 new NodeIdentifierWithPredicates(myDoublyKeyedList, keys))
374 .withChild(Builders.leafBuilder().withNodeIdentifier(
375 new NodeIdentifier(myLeafInList3)).withValue("listleafvalue1").build()).build())
378 AugmentationNode myDoublyKeyedListAugNode = Builders.augmentationBuilder().withNodeIdentifier(
379 new AugmentationIdentifier(Sets.newHashSet(myDoublyKeyedList)))
380 .withChild(myDoublyKeyedListNode).build();
382 ContainerNode myContainer3Node = Builders.containerBuilder().withNodeIdentifier(
383 new NodeIdentifier(myContainer3))
384 .withChild(myDoublyKeyedListAugNode).build();
386 AugmentationNode myContainer3AugNode = Builders.augmentationBuilder().withNodeIdentifier(
387 new AugmentationIdentifier(Sets.newHashSet(myContainer3)))
388 .withChild(myContainer3Node).build();
390 ContainerNode outerContainerNode = Builders.containerBuilder().withNodeIdentifier(
391 new NodeIdentifier(outerContainer))
392 .withChild(myContainer1Node)
393 .withChild(myContainer2Node)
394 .withChild(myContainer3AugNode).build();
396 return outerContainerNode;