Bug 1441: Bug fixes, clean-up and test migration
[yangtools.git] / yang / yang-data-codec-xml / src / test / java / org / opendaylight / yangtools / yang / data / codec / xml / YangModeledAnyXMLSerializationTest.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 com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.StringWriter;
16 import java.net.URI;
17 import javax.xml.parsers.DocumentBuilder;
18 import javax.xml.parsers.DocumentBuilderFactory;
19 import javax.xml.parsers.ParserConfigurationException;
20 import javax.xml.stream.XMLInputFactory;
21 import javax.xml.stream.XMLOutputFactory;
22 import javax.xml.stream.XMLStreamReader;
23 import javax.xml.stream.XMLStreamWriter;
24 import javax.xml.transform.OutputKeys;
25 import javax.xml.transform.Transformer;
26 import javax.xml.transform.TransformerException;
27 import javax.xml.transform.TransformerFactory;
28 import javax.xml.transform.TransformerFactoryConfigurationError;
29 import javax.xml.transform.dom.DOMResult;
30 import javax.xml.transform.dom.DOMSource;
31 import javax.xml.transform.stream.StreamResult;
32 import org.custommonkey.xmlunit.XMLTestCase;
33 import org.custommonkey.xmlunit.XMLUnit;
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.common.SimpleDateFormatUtil;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
40 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
42 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
45 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
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.ContainerSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
51 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
53 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
54 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
55 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
56 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
57 import org.w3c.dom.Document;
58 import org.w3c.dom.Node;
59 import org.xml.sax.SAXException;
60
61 public class YangModeledAnyXMLSerializationTest extends XMLTestCase {
62     private static final DocumentBuilderFactory BUILDERFACTORY;
63
64     static {
65         BUILDERFACTORY = DocumentBuilderFactory.newInstance();
66         BUILDERFACTORY.setNamespaceAware(true);
67         BUILDERFACTORY.setCoalescing(true);
68         BUILDERFACTORY.setIgnoringElementContentWhitespace(true);
69         BUILDERFACTORY.setIgnoringComments(true);
70     }
71
72     private QNameModule bazModuleQName;
73     private QName myAnyXMLDataBaz;
74     private QName bazQName;
75     private QName myContainer2QName;
76     private SchemaContext schemaContext;
77
78     public YangModeledAnyXMLSerializationTest() throws Exception {
79         bazModuleQName = QNameModule.create(new URI("baz"), SimpleDateFormatUtil.getRevisionFormat()
80                 .parse("1970-01-01"));
81         bazQName = QName.create(bazModuleQName, "baz");
82         myContainer2QName = QName.create(bazModuleQName, "my-container-2");
83         myAnyXMLDataBaz = QName.create(bazModuleQName, "my-anyxml-data");
84
85         CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
86         reactor.addSources(new YangStatementSourceImpl("/anyxml-support/serialization/baz.yang", false),
87                 new YangStatementSourceImpl("/anyxml-support/serialization/yang-ext.yang", false));
88         schemaContext = reactor.buildEffective();
89     }
90
91     @Test
92     public void testSerializationOfBaz() throws Exception {
93         final InputStream resourceAsStream = XmlToNormalizedNodesTest.class.getResourceAsStream("/anyxml-support/serialization/baz.xml");
94
95         final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
96         final XMLStreamReader reader = inputFactory.createXMLStreamReader(resourceAsStream);
97
98         final NormalizedNodeResult result = new NormalizedNodeResult();
99
100         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
101
102         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, schemaContext);
103         xmlParser.parse(reader);
104
105         final NormalizedNode<?, ?> transformedInput = result.getResult();
106         assertNotNull(transformedInput);
107
108         assertTrue(transformedInput instanceof ContainerNode);
109         ContainerNode bazContainer = (ContainerNode) transformedInput;
110         assertEquals(bazContainer.getNodeType(), bazQName);
111
112         Optional<DataContainerChild<? extends PathArgument, ?>> bazContainerChild = bazContainer.getChild(
113                 new NodeIdentifier(myAnyXMLDataBaz));
114         assertTrue(bazContainerChild.orNull() instanceof YangModeledAnyXmlNode);
115         YangModeledAnyXmlNode yangModeledAnyXmlNode = (YangModeledAnyXmlNode) bazContainerChild.get();
116
117         DataSchemaNode schemaOfAnyXmlData = yangModeledAnyXmlNode.getSchemaOfAnyXmlData();
118         SchemaNode myContainer2SchemaNode = SchemaContextUtil.findDataSchemaNode(schemaContext,
119                 SchemaPath.create(true, bazQName, myContainer2QName));
120         assertTrue(myContainer2SchemaNode instanceof ContainerSchemaNode);
121         assertEquals(myContainer2SchemaNode, schemaOfAnyXmlData);
122
123         final Document document = getDocument();
124         final DOMResult domResult = new DOMResult(document);
125
126         final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
127         outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
128
129         final XMLStreamWriter xmlStreamWriter = outputFactory.createXMLStreamWriter(domResult);
130
131         final NormalizedNodeStreamWriter xmlNormalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter
132                 .create(xmlStreamWriter, schemaContext);
133
134         final NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter
135                 (xmlNormalizedNodeStreamWriter);
136
137         normalizedNodeWriter.write(transformedInput);
138
139         final Document doc = loadDocument("/anyxml-support/serialization/baz.xml");
140
141         XMLUnit.setIgnoreWhitespace(true);
142         XMLUnit.setIgnoreComments(true);
143         XMLUnit.setIgnoreAttributeOrder(true);
144         XMLUnit.setNormalize(true);
145
146         String expectedXml = toString(doc.getDocumentElement().getElementsByTagName("baz").item(0));
147         String serializedXml = toString(domResult.getNode());
148
149         assertXMLEqual(expectedXml, serializedXml);
150     }
151
152     private static Document loadDocument(final String xmlPath) throws IOException, SAXException {
153         final InputStream resourceAsStream = YangModeledAnyXMLSerializationTest.class.getResourceAsStream(xmlPath);
154         final Document currentConfigElement = readXmlToDocument(resourceAsStream);
155         Preconditions.checkNotNull(currentConfigElement);
156         return currentConfigElement;
157     }
158
159     private static Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
160         final DocumentBuilder dBuilder;
161         try {
162             dBuilder = BUILDERFACTORY.newDocumentBuilder();
163         } catch (final ParserConfigurationException e) {
164             throw new RuntimeException("Failed to parse XML document", e);
165         }
166         final Document doc = dBuilder.parse(xmlContent);
167
168         doc.getDocumentElement().normalize();
169         return doc;
170     }
171
172     private static String toString(final Node xml) {
173         try {
174             final Transformer transformer = TransformerFactory.newInstance().newTransformer();
175             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
176             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
177
178             final StreamResult result = new StreamResult(new StringWriter());
179             final DOMSource source = new DOMSource(xml);
180             transformer.transform(source, result);
181
182             return result.getWriter().toString();
183         } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
184             throw new RuntimeException("Unable to serialize xml element " + xml, e);
185         }
186     }
187
188     private static Document getDocument() {
189         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
190         Document doc = null;
191         try {
192             DocumentBuilder bob = dbf.newDocumentBuilder();
193             doc = bob.newDocument();
194         } catch (ParserConfigurationException e) {
195             throw new RuntimeException(e);
196         }
197         return doc;
198     }
199 }