7868c2203a854cf2433d98cade1e4d63089b568b
[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
9 package org.opendaylight.yangtools.yang.data.codec.xml;
10
11 import static org.hamcrest.CoreMatchers.containsString;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertThat;
15 import static org.junit.Assert.assertTrue;
16
17 import com.google.common.base.Optional;
18 import com.google.common.collect.Maps;
19 import java.io.ByteArrayOutputStream;
20 import java.io.FileNotFoundException;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23 import java.util.AbstractMap;
24 import java.util.Date;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 import javax.xml.stream.XMLOutputFactory;
29 import javax.xml.stream.XMLStreamWriter;
30 import org.custommonkey.xmlunit.Diff;
31 import org.custommonkey.xmlunit.XMLUnit;
32 import org.junit.BeforeClass;
33 import org.junit.Ignore;
34 import org.junit.Test;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.common.QNameModule;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.Module;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
44 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
45 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
46 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
48 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
49 import org.w3c.dom.Document;
50
51 public class XmlStreamUtilsTest {
52
53     public static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
54
55     private static SchemaContext schemaContext;
56     private static Module leafRefModule;
57
58     @BeforeClass
59     public static void initialize() throws URISyntaxException, FileNotFoundException, ReactorException {
60         schemaContext = YangParserTestUtils.parseYangSource("/leafref-test.yang");
61         assertNotNull(schemaContext);
62         assertEquals(1, schemaContext.getModules().size());
63         leafRefModule = schemaContext.getModules().iterator().next();
64         assertNotNull(leafRefModule);
65     }
66
67     @Test
68     public void testWriteAttribute() throws Exception {
69         final ByteArrayOutputStream out = new ByteArrayOutputStream();
70         final XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
71         writer.writeStartElement("element");
72
73         QName name = getAttrQName("namespace", "2012-12-12", "attr", Optional.of("prefix"));
74         final Map.Entry<QName, String> attributeEntry = new AbstractMap.SimpleEntry<>(name, "value");
75
76         name = getAttrQName("namespace2", "2012-12-12", "attr", Optional.absent());
77         final Map.Entry<QName, String> attributeEntryNoPrefix = new AbstractMap.SimpleEntry<>(name, "value");
78
79         final RandomPrefix randomPrefix = new RandomPrefix(null);
80         XMLStreamWriterUtils.writeAttribute(writer, attributeEntry, randomPrefix);
81         XMLStreamWriterUtils.writeAttribute(writer, attributeEntryNoPrefix, randomPrefix);
82
83         writer.writeEndElement();
84         writer.close();
85         out.close();
86
87         final String xmlAsString = new String(out.toByteArray());
88
89         final Map<String, String> mappedPrefixes = mapPrefixed(randomPrefix.getPrefixes());
90         assertEquals(2, mappedPrefixes.size());
91         final String randomPrefixValue = mappedPrefixes.get("namespace2");
92
93         final String expectedXmlAsString = "<element xmlns:a=\"namespace\" a:attr=\"value\" xmlns:" + randomPrefixValue
94                 + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
95
96         XMLUnit.setIgnoreAttributeOrder(true);
97         final Document control = XMLUnit.buildControlDocument(expectedXmlAsString);
98         final Document test = XMLUnit.buildTestDocument(xmlAsString);
99         final Diff diff = XMLUnit.compareXML(control, test);
100
101         final boolean identical = diff.identical();
102         assertTrue("Xml differs: " + diff.toString(), identical);
103     }
104
105     @Test
106     public void testWriteIdentityRef() throws Exception {
107         final ByteArrayOutputStream out = new ByteArrayOutputStream();
108         final XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
109
110         writer.writeStartElement("element");
111         final QNameModule parent = QNameModule.create(URI.create("parent:uri"), new Date());
112         XMLStreamWriterUtils.write(writer, null, QName.create(parent, "identity"), parent);
113         writer.writeEndElement();
114
115         writer.writeStartElement("elementDifferent");
116         XMLStreamWriterUtils.write(writer, null, QName.create("different:namespace", "identity"), parent);
117         writer.writeEndElement();
118
119         writer.close();
120         out.close();
121
122         final String xmlAsString = new String(out.toByteArray()).replaceAll("\\s*", "");
123         assertThat(xmlAsString, containsString("element>identity"));
124
125         final Pattern prefixedIdentityPattern = Pattern.compile(".*\"different:namespace\">(.*):identity.*");
126         final Matcher matcher = prefixedIdentityPattern.matcher(xmlAsString);
127         assertTrue("Xml: " + xmlAsString + " should match: " + prefixedIdentityPattern, matcher.matches());
128     }
129
130     /**
131      * One leafref reference to other leafref via relative references.
132      */
133     @Test
134     public void testLeafRefRelativeChaining() {
135         getTargetNodeForLeafRef("leafname3", StringTypeDefinition.class);
136     }
137
138     @Test
139     public void testLeafRefRelative() {
140         getTargetNodeForLeafRef("pointToStringLeaf", StringTypeDefinition.class);
141     }
142
143     @Test
144     public void testLeafRefAbsoluteWithSameTarget() {
145         getTargetNodeForLeafRef("absname", InstanceIdentifierTypeDefinition.class);
146     }
147
148     /**
149      * Tests relative path with double point inside path (e. g. "../../lf:interface/../lf:cont2/lf:stringleaf")
150      */
151     // ignored because this isn't implemented
152     @Ignore
153     @Test
154     public void testLeafRefWithDoublePointInPath() {
155         getTargetNodeForLeafRef("lf-with-double-point-inside", StringTypeDefinition.class);
156     }
157
158     @Test
159     public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
160         final TypeDefinition<?> targetNodeForAbsname = getTargetNodeForLeafRef("absname",
161             InstanceIdentifierTypeDefinition.class);
162         final TypeDefinition<?> targetNodeForRelname = getTargetNodeForLeafRef("relname",
163             InstanceIdentifierTypeDefinition.class);
164         assertEquals(targetNodeForAbsname, targetNodeForRelname);
165     }
166
167     private TypeDefinition<?> getTargetNodeForLeafRef(final String nodeName, final Class<?> clas) {
168         final LeafSchemaNode schemaNode = findSchemaNodeWithLeafrefType(leafRefModule, nodeName);
169         assertNotNull(schemaNode);
170         final LeafrefTypeDefinition leafrefTypedef = findLeafrefType(schemaNode);
171         assertNotNull(leafrefTypedef);
172         final TypeDefinition<?> targetBaseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypedef, schemaContext,
173                 schemaNode);
174         assertTrue("Wrong class found.", clas.isInstance(targetBaseType));
175         return targetBaseType;
176     }
177
178     private static Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
179         final Map<String, String> mappedPrefixes = Maps.newHashMap();
180         for (final Map.Entry<URI, String> prefix : prefixes) {
181             mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
182         }
183         return mappedPrefixes;
184     }
185
186     private static QName getAttrQName(final String namespace, final String revision, final String localName,
187             final Optional<String> prefix) {
188         if (prefix.isPresent()) {
189             final QName moduleQName = QName.create(namespace, revision, "module");
190             final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
191             return QName.create(module, localName);
192         }
193         return QName.create(namespace, revision, localName);
194     }
195
196     private LeafSchemaNode findSchemaNodeWithLeafrefType(final DataNodeContainer module, final String nodeName) {
197         for (final DataSchemaNode childNode : module.getChildNodes()) {
198             if (childNode instanceof DataNodeContainer) {
199                 LeafSchemaNode leafrefFromRecursion = findSchemaNodeWithLeafrefType((DataNodeContainer) childNode,
200                         nodeName);
201                 if (leafrefFromRecursion != null) {
202                     return leafrefFromRecursion;
203                 }
204             } else if (childNode.getQName().getLocalName().equals(nodeName) && childNode instanceof LeafSchemaNode) {
205                 final TypeDefinition<?> leafSchemaNodeType = ((LeafSchemaNode) childNode).getType();
206                 if (leafSchemaNodeType instanceof LeafrefTypeDefinition) {
207                     return (LeafSchemaNode) childNode;
208                 }
209             }
210         }
211         return null;
212     }
213
214     private static LeafrefTypeDefinition findLeafrefType(final LeafSchemaNode schemaNode) {
215         final TypeDefinition<?> type = schemaNode.getType();
216         if (type instanceof LeafrefTypeDefinition) {
217             return (LeafrefTypeDefinition) type;
218         }
219         return null;
220     }
221 }