Merge "Make sure YangInstanceIdentifier.EMPTY is retained"
[yangtools.git] / yang / yang-data-impl / src / test / java / org / opendaylight / yangtools / yang / data / impl / codec / xml / XmlStreamUtilsTest.java
1 /*
2  * Copyright (c) 2014 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.impl.codec.xml;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14
15 import com.google.common.base.Optional;
16 import com.google.common.collect.Maps;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.AbstractMap;
22 import java.util.Arrays;
23 import java.util.Map;
24 import javax.xml.stream.XMLOutputFactory;
25 import javax.xml.stream.XMLStreamWriter;
26 import org.custommonkey.xmlunit.Diff;
27 import org.custommonkey.xmlunit.XMLUnit;
28 import org.junit.BeforeClass;
29 import org.junit.Ignore;
30 import org.junit.Test;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.common.QNameModule;
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.LeafrefTypeDefinition;
40 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
41 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
42 import org.opendaylight.yangtools.yang.model.util.StringType;
43 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
44 import org.w3c.dom.Document;
45
46 public class XmlStreamUtilsTest {
47
48     public static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
49
50     private static SchemaContext schemaContext;
51     private static Module leafRefModule;
52
53     @BeforeClass
54     public static void initialize() throws URISyntaxException {
55         final YangParserImpl yangParser = new YangParserImpl();
56         final File file = new File(XmlStreamUtils.class.getResource("/leafref-test.yang").toURI());
57         schemaContext = yangParser.parseFiles(Arrays.asList(file));
58         assertNotNull(schemaContext);
59         assertEquals(1,schemaContext.getModules().size());
60         leafRefModule = schemaContext.getModules().iterator().next();
61         assertNotNull(leafRefModule);
62     }
63
64
65     @Test
66     public void testWriteAttribute() throws Exception {
67         final ByteArrayOutputStream out = new ByteArrayOutputStream();
68         final XMLStreamWriter writer =  XML_OUTPUT_FACTORY.createXMLStreamWriter(out);
69         writer.writeStartElement("element");
70
71         QName name = getAttrQName("namespace", "2012-12-12", "attr", Optional.of("prefix"));
72         final Map.Entry<QName, String> attributeEntry = new AbstractMap.SimpleEntry<>(name, "value");
73
74         name = getAttrQName("namespace2", "2012-12-12", "attr", Optional.<String>absent());
75         final Map.Entry<QName, String> attributeEntryNoPrefix = new AbstractMap.SimpleEntry<>(name, "value");
76
77         final RandomPrefix randomPrefix = new RandomPrefix();
78         XmlStreamUtils.writeAttribute(writer, attributeEntry, randomPrefix);
79         XmlStreamUtils.writeAttribute(writer, attributeEntryNoPrefix, randomPrefix);
80
81         writer.writeEndElement();
82         writer.close();
83         out.close();
84
85         final String xmlAsString = new String(out.toByteArray());
86
87         final Map<String, String> mappedPrefixes = mapPrefixed(randomPrefix.getPrefixes());
88         assertEquals(2, mappedPrefixes.size());
89         final String randomPrefixValue = mappedPrefixes.get("namespace2");
90
91         final String expectedXmlAsString = "<element xmlns:a=\"namespace\" a:attr=\"value\" xmlns:" + randomPrefixValue + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
92
93         XMLUnit.setIgnoreAttributeOrder(true);
94         final Document control = XMLUnit.buildControlDocument(expectedXmlAsString);
95         final Document test = XMLUnit.buildTestDocument(xmlAsString);
96         final Diff diff = XMLUnit.compareXML(control, test);
97
98         final boolean identical = diff.identical();
99         assertTrue("Xml differs: " + diff.toString(), identical);
100     }
101
102     /**
103      * One leafref reference to other leafref via relative references
104      */
105     @Test
106     public void testLeafRefRelativeChaining() {
107         getTargetNodeForLeafRef("leafname3",StringType.class);
108     }
109
110     @Test
111     public void testLeafRefRelative() {
112         getTargetNodeForLeafRef("pointToStringLeaf",StringType.class);
113     }
114
115     @Test
116     public void testLeafRefAbsoluteWithSameTarget() {
117         getTargetNodeForLeafRef("absname",InstanceIdentifierType.class);
118     }
119
120     /**
121      * Tests relative path with double point inside path (e. g. "../../lf:interface/../lf:cont2/lf:stringleaf")
122      */
123     @Ignore //ignored because this isn't implemented
124     @Test
125     public void testLeafRefWithDoublePointInPath() {
126         getTargetNodeForLeafRef("lf-with-double-point-inside",StringType.class);
127     }
128
129     @Test
130     public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
131         final TypeDefinition<?> targetNodeForAbsname = getTargetNodeForLeafRef("absname",InstanceIdentifierType.class);
132         final TypeDefinition<?> targetNodeForRelname = getTargetNodeForLeafRef("relname",InstanceIdentifierType.class);
133         assertEquals(targetNodeForAbsname, targetNodeForRelname);
134     }
135
136     private TypeDefinition<?> getTargetNodeForLeafRef(final String nodeName, final Class<?> clas) {
137         final LeafSchemaNode schemaNode = findSchemaNodeWithLeafrefType(leafRefModule, nodeName);
138         assertNotNull(schemaNode);
139         final LeafrefTypeDefinition leafrefTypedef = findLeafrefType(schemaNode);
140         assertNotNull(leafrefTypedef);
141         final TypeDefinition<?> targetBaseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypedef, schemaContext, schemaNode);
142         assertEquals("Wrong class found.", clas, targetBaseType.getClass());
143         return targetBaseType;
144     }
145
146     private Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
147         final Map<String, String> mappedPrefixes = Maps.newHashMap();
148         for (final Map.Entry<URI, String> prefix : prefixes) {
149             mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
150         }
151         return mappedPrefixes;
152     }
153
154     private QName getAttrQName(final String namespace, final String revision, final String localName, final Optional<String> prefix) {
155
156         if(prefix.isPresent()) {
157             final QName moduleQName = QName.create(namespace, revision, "module");
158             final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
159             return QName.create(module, localName);
160         } else {
161             return QName.create(namespace, revision, localName);
162         }
163     }
164
165     private LeafSchemaNode findSchemaNodeWithLeafrefType(final DataNodeContainer module, final String nodeName) {
166         for (final DataSchemaNode childNode : module.getChildNodes()) {
167             if (childNode instanceof DataNodeContainer) {
168                 LeafSchemaNode leafrefFromRecursion = findSchemaNodeWithLeafrefType((DataNodeContainer)childNode, nodeName);
169                 if (leafrefFromRecursion != null) {
170                     return leafrefFromRecursion;
171                 }
172             } else if (childNode.getQName().getLocalName().equals(nodeName) && childNode instanceof LeafSchemaNode) {
173                 final TypeDefinition<?> leafSchemaNodeType = ((LeafSchemaNode)childNode).getType();
174                 if (leafSchemaNodeType instanceof LeafrefTypeDefinition) {
175                     return (LeafSchemaNode)childNode;
176                 }
177             }
178         }
179         return null;
180     }
181
182     private LeafrefTypeDefinition findLeafrefType(final LeafSchemaNode schemaNode) {
183         final TypeDefinition<?> type = schemaNode.getType();
184         if (type instanceof LeafrefTypeDefinition) {
185             return (LeafrefTypeDefinition)type;
186         }
187         return null;
188     }
189 }