c01e948b5f75f0ac83186797f422c81ae4f93933
[yangtools.git] / codec / yang-data-codec-xml / src / test / java / org / opendaylight / yangtools / yang / data / codec / xml / XmlStreamUtilsTest.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.CoreMatchers.instanceOf;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertSame;
16 import static org.junit.Assert.assertTrue;
17
18 import java.io.ByteArrayOutputStream;
19 import java.io.IOException;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamWriter;
24 import org.junit.AfterClass;
25 import org.junit.BeforeClass;
26 import org.junit.Ignore;
27 import org.junit.Test;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.common.QNameModule;
30 import org.opendaylight.yangtools.yang.common.Revision;
31 import org.opendaylight.yangtools.yang.common.XMLNamespace;
32 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
33 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.Module;
35 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
38 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
41 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
42 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
43
44 public class XmlStreamUtilsTest {
45     @FunctionalInterface
46     interface XMLStreamWriterConsumer {
47         void accept(XMLStreamWriter writer) throws XMLStreamException;
48     }
49
50     private static EffectiveModelContext modelContext;
51     private static Module leafRefModule;
52     private static PreferredPrefixes pref;
53
54     @BeforeClass
55     public static void initialize() {
56         modelContext = YangParserTestUtils.parseYangResource("/leafref-test.yang");
57         assertNotNull(modelContext);
58         assertEquals(1, modelContext.getModules().size());
59         leafRefModule = modelContext.getModules().iterator().next();
60         assertNotNull(leafRefModule);
61         pref = new PreferredPrefixes.Shared(modelContext);
62     }
63
64     @AfterClass
65     public static void cleanup() {
66         leafRefModule = null;
67         modelContext = null;
68     }
69
70     @Test
71     public void testWriteIdentityRef() throws Exception {
72         final QNameModule parent = QNameModule.create(XMLNamespace.of("parent:uri"), Revision.of("2000-01-01"));
73
74         String xmlAsString = createXml(writer -> {
75             writer.writeStartElement("element");
76             final var facade = new StreamWriterFacade(writer, pref);
77             facade.writeCharacters(XMLStreamWriterUtils.encode(facade, QName.create(parent, "identity"), parent));
78             facade.flush();
79             writer.writeEndElement();
80         });
81
82         assertThat(xmlAsString, containsString("element>identity"));
83
84         xmlAsString = createXml(writer -> {
85             writer.writeStartElement("elementDifferent");
86             final var facade = new StreamWriterFacade(writer, pref);
87             facade.writeCharacters(XMLStreamWriterUtils.encode(facade, QName.create("different:namespace", "identity"),
88                 parent));
89             facade.flush();
90             writer.writeEndElement();
91         });
92
93         final Pattern prefixedIdentityPattern = Pattern.compile(".*\"different:namespace\">(.*):identity.*");
94         final Matcher matcher = prefixedIdentityPattern.matcher(xmlAsString);
95         assertTrue("Xml: " + xmlAsString + " should match: " + prefixedIdentityPattern, matcher.matches());
96     }
97
98     private static String createXml(final XMLStreamWriterConsumer consumer) throws XMLStreamException, IOException {
99         final ByteArrayOutputStream out = new ByteArrayOutputStream();
100         final XMLStreamWriter writer = TestFactories.DEFAULT_OUTPUT_FACTORY.createXMLStreamWriter(out);
101
102         consumer.accept(writer);
103
104         writer.close();
105         out.close();
106
107         return new String(out.toByteArray()).replaceAll("\\s*", "");
108     }
109
110     /**
111      * One leafref reference to other leafref via relative references.
112      */
113     @Test
114     public void testLeafRefRelativeChaining() {
115         getTargetNodeForLeafRef(StringTypeDefinition.class, "cont3", "leafname3");
116     }
117
118     @Test
119     public void testLeafRefRelative() {
120         getTargetNodeForLeafRef(StringTypeDefinition.class, "pointToStringLeaf");
121     }
122
123     @Test
124     public void testLeafRefAbsoluteWithSameTarget() {
125         getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "absname");
126     }
127
128     /**
129      * Tests relative path with double point inside path (e. g. "../../lf:interface/../lf:cont2/lf:stringleaf")
130      */
131     // ignored because this isn't implemented
132     @Ignore
133     @Test
134     public void testLeafRefWithDoublePointInPath() {
135         getTargetNodeForLeafRef(StringTypeDefinition.class, "lf-with-double-point-inside");
136     }
137
138     @Test
139     public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
140         assertSame(getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "absname"),
141             getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "relname"));
142     }
143
144     private static TypeDefinition<?> getTargetNodeForLeafRef(final Class<?> clas, final String... names) {
145         final SchemaInferenceStack stack = SchemaInferenceStack.of(modelContext);
146         stack.enterDataTree(QName.create(leafRefModule.getQNameModule(), "cont2"));
147         for (String name : names) {
148             stack.enterDataTree(QName.create(leafRefModule.getQNameModule(), name));
149         }
150
151         final EffectiveStatement<?, ?> leaf = stack.currentStatement();
152         assertThat(leaf, instanceOf(LeafSchemaNode.class));
153         final TypeDefinition<? extends TypeDefinition<?>> type = ((TypedDataSchemaNode) leaf).getType();
154         assertThat(type, instanceOf(LeafrefTypeDefinition.class));
155
156         final TypeDefinition<?> resolved = stack.resolveLeafref((LeafrefTypeDefinition) type);
157         assertThat(resolved, instanceOf(clas));
158         return resolved;
159     }
160 }