d193f7e21f5da48576839b409d734868922b5fe8
[yangtools.git] / yang / 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.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertTrue;
15
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.net.URI;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Optional;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24 import javax.xml.stream.XMLStreamException;
25 import javax.xml.stream.XMLStreamWriter;
26 import org.junit.AfterClass;
27 import org.junit.BeforeClass;
28 import org.junit.Ignore;
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.Revision;
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.Module;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
41 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
42 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
43 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
44
45 public class XmlStreamUtilsTest {
46     @FunctionalInterface
47     interface XMLStreamWriterConsumer {
48         void accept(XMLStreamWriter writer) throws XMLStreamException;
49     }
50
51     private static SchemaContext schemaContext;
52     private static Module leafRefModule;
53
54     @BeforeClass
55     public static void initialize() {
56         schemaContext = YangParserTestUtils.parseYangResource("/leafref-test.yang");
57         assertNotNull(schemaContext);
58         assertEquals(1, schemaContext.getModules().size());
59         leafRefModule = schemaContext.getModules().iterator().next();
60         assertNotNull(leafRefModule);
61     }
62
63     @AfterClass
64     public static void cleanup() {
65         leafRefModule = null;
66         schemaContext = null;
67     }
68
69     @Test
70     public void testWriteIdentityRef() throws Exception {
71         final QNameModule parent = QNameModule.create(URI.create("parent:uri"), Revision.of("2000-01-01"));
72
73         String xmlAsString = createXml(writer -> {
74             writer.writeStartElement("element");
75             final StreamWriterFacade facade = new StreamWriterFacade(writer);
76             facade.writeCharacters(XMLStreamWriterUtils.encode(facade, null, QName.create(parent, "identity"), parent));
77             facade.flush();
78             writer.writeEndElement();
79         });
80
81         assertThat(xmlAsString, containsString("element>identity"));
82
83         xmlAsString = createXml(writer -> {
84             writer.writeStartElement("elementDifferent");
85             final StreamWriterFacade facade = new StreamWriterFacade(writer);
86             facade.writeCharacters(XMLStreamWriterUtils.encode(facade, null, QName.create("different:namespace",
87                 "identity"), parent));
88             facade.flush();
89             writer.writeEndElement();
90         });
91
92         final Pattern prefixedIdentityPattern = Pattern.compile(".*\"different:namespace\">(.*):identity.*");
93         final Matcher matcher = prefixedIdentityPattern.matcher(xmlAsString);
94         assertTrue("Xml: " + xmlAsString + " should match: " + prefixedIdentityPattern, matcher.matches());
95     }
96
97     private static String createXml(final XMLStreamWriterConsumer consumer) throws XMLStreamException, IOException {
98         final ByteArrayOutputStream out = new ByteArrayOutputStream();
99         final XMLStreamWriter writer = TestFactories.DEFAULT_OUTPUT_FACTORY.createXMLStreamWriter(out);
100
101         consumer.accept(writer);
102
103         writer.close();
104         out.close();
105
106         return new String(out.toByteArray()).replaceAll("\\s*", "");
107     }
108
109     /**
110      * One leafref reference to other leafref via relative references.
111      */
112     @Test
113     public void testLeafRefRelativeChaining() {
114         getTargetNodeForLeafRef("leafname3", StringTypeDefinition.class);
115     }
116
117     @Test
118     public void testLeafRefRelative() {
119         getTargetNodeForLeafRef("pointToStringLeaf", StringTypeDefinition.class);
120     }
121
122     @Test
123     public void testLeafRefAbsoluteWithSameTarget() {
124         getTargetNodeForLeafRef("absname", InstanceIdentifierTypeDefinition.class);
125     }
126
127     /**
128      * Tests relative path with double point inside path (e. g. "../../lf:interface/../lf:cont2/lf:stringleaf")
129      */
130     // ignored because this isn't implemented
131     @Ignore
132     @Test
133     public void testLeafRefWithDoublePointInPath() {
134         getTargetNodeForLeafRef("lf-with-double-point-inside", StringTypeDefinition.class);
135     }
136
137     @Test
138     public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
139         final TypeDefinition<?> targetNodeForAbsname = getTargetNodeForLeafRef("absname",
140             InstanceIdentifierTypeDefinition.class);
141         final TypeDefinition<?> targetNodeForRelname = getTargetNodeForLeafRef("relname",
142             InstanceIdentifierTypeDefinition.class);
143         assertEquals(targetNodeForAbsname, targetNodeForRelname);
144     }
145
146     private TypeDefinition<?> getTargetNodeForLeafRef(final String nodeName, final Class<?> clas) {
147         final LeafSchemaNode schemaNode = findSchemaNodeWithLeafrefType(leafRefModule, nodeName);
148         assertNotNull(schemaNode);
149         final LeafrefTypeDefinition leafrefTypedef = findLeafrefType(schemaNode);
150         assertNotNull(leafrefTypedef);
151         final TypeDefinition<?> targetBaseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypedef, schemaContext,
152                 schemaNode);
153         assertTrue("Wrong class found.", clas.isInstance(targetBaseType));
154         return targetBaseType;
155     }
156
157     private static Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
158         final Map<String, String> mappedPrefixes = new HashMap<>();
159         for (final Map.Entry<URI, String> prefix : prefixes) {
160             mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
161         }
162         return mappedPrefixes;
163     }
164
165     private static QName getAttrQName(final String namespace, final String revision, final String localName,
166             final Optional<String> prefix) {
167         if (prefix.isPresent()) {
168             final QName moduleQName = QName.create(namespace, revision, "module");
169             final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
170             return QName.create(module, localName);
171         }
172         return QName.create(namespace, revision, localName);
173     }
174
175     private LeafSchemaNode findSchemaNodeWithLeafrefType(final DataNodeContainer module, final String nodeName) {
176         for (final DataSchemaNode childNode : module.getChildNodes()) {
177             if (childNode instanceof DataNodeContainer) {
178                 LeafSchemaNode leafrefFromRecursion = findSchemaNodeWithLeafrefType((DataNodeContainer) childNode,
179                         nodeName);
180                 if (leafrefFromRecursion != null) {
181                     return leafrefFromRecursion;
182                 }
183             } else if (childNode.getQName().getLocalName().equals(nodeName) && childNode instanceof LeafSchemaNode) {
184                 final TypeDefinition<?> leafSchemaNodeType = ((LeafSchemaNode) childNode).getType();
185                 if (leafSchemaNodeType instanceof LeafrefTypeDefinition) {
186                     return (LeafSchemaNode) childNode;
187                 }
188             }
189         }
190         return null;
191     }
192
193     private static LeafrefTypeDefinition findLeafrefType(final LeafSchemaNode schemaNode) {
194         final TypeDefinition<?> type = schemaNode.getType();
195         if (type instanceof LeafrefTypeDefinition) {
196             return (LeafrefTypeDefinition) type;
197         }
198         return null;
199     }
200 }