--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yangtools.yang.model.export.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.base.Preconditions;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.export.YinExportUtils;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+public class SchemaContextEmitterTest {
+
+ @Test
+ public void testSchemaContextEmitter() throws ReactorException, IOException, URISyntaxException,
+ XMLStreamException, SAXException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSources("/schema-context-emitter-test");
+ assertNotNull(schemaContext);
+ assertEquals(1, schemaContext.getModules().size());
+
+ final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
+
+ for (Module module : schemaContext.getModules()) {
+ YinExportUtils.writeModuleToOutputStream(schemaContext, module, bufferedOutputStream);
+ }
+
+ final String output = byteArrayOutputStream.toString();
+ assertNotNull(output);
+ assertNotEquals(0, output.length());
+
+ final Document doc = loadDocument("/schema-context-emitter-test/foo.xml");
+ final String expected = toString(doc.getDocumentElement());
+
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setNormalize(true);
+
+ final Diff diff = new Diff(expected, output);
+ diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
+ XMLAssert.assertXMLEqual(diff, true);
+ }
+
+ private static Document loadDocument(final String xmlPath) throws IOException, SAXException {
+ final InputStream resourceAsStream = SchemaContextEmitterTest.class.getResourceAsStream(xmlPath);
+ final Document currentConfigElement = readXmlToDocument(resourceAsStream);
+ Preconditions.checkNotNull(currentConfigElement);
+ return currentConfigElement;
+ }
+
+ private static Document readXmlToDocument(final InputStream xmlContent) throws IOException, SAXException {
+ final DocumentBuilder dBuilder;
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setCoalescing(true);
+ factory.setIgnoringElementContentWhitespace(true);
+ factory.setIgnoringComments(true);
+ dBuilder = factory.newDocumentBuilder();
+ } catch (final ParserConfigurationException e) {
+ throw new RuntimeException("Failed to parse XML document", e);
+ }
+ final Document doc = dBuilder.parse(xmlContent);
+
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ private static String toString(final Node xml) {
+ try {
+ final Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+ final StreamResult result = new StreamResult(new StringWriter());
+ final DOMSource source = new DOMSource(xml);
+ transformer.transform(source, result);
+
+ return result.getWriter().toString();
+ } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
+ throw new RuntimeException("Unable to serialize xml element " + xml, e);
+ }
+ }
+}
--- /dev/null
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:foo-prefix="foo-namespace" name="foo">
+ <yang-version value="1"></yang-version>
+ <namespace uri="foo-namespace"></namespace>
+ <prefix value="foo-prefix"></prefix>
+ <organization>
+ <text></text>
+ </organization>
+ <contact>
+ <text></text>
+ </contact>
+ <revision date="2016-08-05"></revision>
+ <extension name="test-extension">
+ <status value="current"></status>
+ </extension>
+ <feature name="test-feature">
+ <status value="current"></status>
+ <description>
+ <text>test-feature description</text>
+ </description>
+ <reference>
+ <text>test-feature reference</text>
+ </reference>
+ </feature>
+ <identity name="test-identity">
+ <base name="test-base-identity"></base>
+ <status value="current"></status>
+ <description>
+ <text>test-identity description</text>
+ </description>
+ <reference>
+ <text>test-identity reference</text>
+ </reference>
+ </identity>
+ <identity name="test-base-identity">
+ <status value="current"></status>
+ </identity>
+ <typedef name="test-uint32-typedef">
+ <type name="uint32">
+ <range value="50..100">
+ <error-message>
+ <value>The argument is out of bounds <50, 100></value>
+ </error-message>
+ <error-app-tag value="range-out-of-specified-bounds"></error-app-tag>
+ </range>
+ </type>
+ <units name="seconds"></units>
+ <status value="current"></status>
+ </typedef>
+ <typedef name="test-int32-typedef">
+ <type name="int32">
+ <range value="50..100">
+ <error-message>
+ <value>The argument is out of bounds <50, 100></value>
+ </error-message>
+ <error-app-tag value="range-out-of-specified-bounds"></error-app-tag>
+ </range>
+ </type>
+ <status value="current"></status>
+ </typedef>
+ <typedef name="test-leafref-typedef">
+ <type name="leafref">
+ <path value="../leafref-target-leaf"></path>
+ </type>
+ <status value="current"></status>
+ </typedef>
+ <typedef name="test-iid-typedef">
+ <type name="instance-identifier">
+ <require-instance value="false"></require-instance>
+ </type>
+ <status value="current"></status>
+ </typedef>
+ <grouping name="test-grouping-1">
+ <status value="current"></status>
+ <leaf name="test-leaf-1">
+ <type name="string"></type>
+ <default value="def-val"></default>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ <leaf-list name="test-leaf-list">
+ <type name="string"></type>
+ <config value="false"></config>
+ <min-elements value="0"></min-elements>
+ <max-elements value="2147483647"></max-elements>
+ <ordered-by value="user"></ordered-by>
+ <status value="current"></status>
+ </leaf-list>
+ <list name="test-list">
+ <key value="key-leaf-1 key-leaf-2"></key>
+ <config value="true"></config>
+ <min-elements value="5"></min-elements>
+ <max-elements value="2147483647"></max-elements>
+ <ordered-by value="system"></ordered-by>
+ <status value="current"></status>
+ <leaf name="key-leaf-1">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ <leaf name="key-leaf-2">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </list>
+ <container name="test-container-2">
+ <presence value="false"></presence>
+ <config value="false"></config>
+ <status value="current"></status>
+ </container>
+ </grouping>
+ <grouping name="test-grouping-2">
+ <status value="current"></status>
+ <anyxml name="test-anyxml-2">
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </anyxml>
+ <choice name="test-choice-2">
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ <case name="first">
+ <status value="current"></status>
+ <leaf name="first-case-leaf">
+ <type name="string">
+ <length value="10|15">
+ <error-message>
+ <value>The argument is out of bounds <10, 10></value>
+ </error-message>
+ <error-app-tag value="length-out-of-specified-bounds"></error-app-tag>
+ </length>
+ </type>
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </case>
+ <case name="second">
+ <status value="current"></status>
+ <leaf name="second-case-leaf">
+ <type name="int32">
+ <range value="10|15">
+ <error-message>
+ <value>The argument is out of bounds <10, 10></value>
+ </error-message>
+ <error-app-tag value="range-out-of-specified-bounds"></error-app-tag>
+ </range>
+ </type>
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </case>
+ </choice>
+ </grouping>
+ <anyxml name="test-anyxml">
+ <when condition="foo != 'bar'"></when>
+ <must condition="bar != 'foo'"></must>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ <foo-prefix:test-extension></foo-prefix:test-extension>
+ </anyxml>
+ <leaf name="leafref-target-leaf">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ <container name="test-container-1">
+ <must condition="bar != 'foo'"></must>
+ <must condition="bar != 'foo'"></must>
+ <presence value="false"></presence>
+ <config value="true"></config>
+ <status value="current"></status>
+ </container>
+ <container name="test-container-3">
+ <presence value="false"></presence>
+ <config value="true"></config>
+ <status value="current"></status>
+ <choice name="test-choice">
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ <case name="a">
+ <status value="current"></status>
+ <leaf name="case-a-leaf">
+ <type name="int32"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </case>
+ <case name="b">
+ <status value="current"></status>
+ <leaf name="case-b-leaf">
+ <type name="decimal64">
+ <fraction-digits value="3"></fraction-digits>
+ <range value="-9223372036854775.808..9223372036854775.807">
+ <error-message>
+ <value>The argument is out of bounds <-9223372036854775.808, 9223372036854775.807></value>
+ </error-message>
+ <error-app-tag value="range-out-of-specified-bounds"></error-app-tag>
+ <reference>
+ <text>https://tools.ietf.org/html/rfc6020#section-9.3.4</text>
+ </reference>
+ </range>
+ </type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </case>
+ </choice>
+ <leaf name="bits-leaf">
+ <type name="bits">
+ <bit name="one">
+ <position value="1"></position>
+ <status value="current"></status>
+ </bit>
+ <bit name="two">
+ <position value="2"></position>
+ <status value="current"></status>
+ </bit>
+ </type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ <leaf name="identityref-leaf">
+ <type name="identityref">
+ <base name="identityref"></base>
+ </type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </container>
+ <augment target-node="/test-container-3/test-choice">
+ <status value="current"></status>
+ <case name="c">
+ <status value="current"></status>
+ <leaf name="case-c-leaf">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </case>
+ </augment>
+ <augment target-node="/test-container-1">
+ <status value="current"></status>
+ <uses name="test-grouping-1">
+ <refine target-node="test-list">
+ <config value="true"></config>
+ <min-elements value="5"></min-elements>
+ <max-elements value="2147483647"></max-elements>
+ </refine>
+ <refine target-node="test-leaf-list">
+ <config value="false"></config>
+ <min-elements value="0"></min-elements>
+ <max-elements value="2147483647"></max-elements>
+ </refine>
+ <refine target-node="test-leaf-1">
+ <default value="def-val"></default>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ </refine>
+ <refine target-node="test-container-2">
+ <presence value="false"></presence>
+ <config value="false"></config>
+ </refine>
+ <augment target-node="test-container-2">
+ <status value="current"></status>
+ <leaf name="test-leaf-2">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </augment>
+ </uses>
+ </augment>
+ <rpc name="test-rpc">
+ <status value="current"></status>
+ <grouping name="rpc-grouping">
+ <status value="current"></status>
+ <leaf name="rpc-grouping-leaf">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </grouping>
+ <input>
+ <leaf name="input-leaf">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </input>
+ <output>
+ <leaf name="output-leaf">
+ <type name="string"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ </output>
+ </rpc>
+ <notification name="test-notification">
+ <status value="current"></status>
+ <uses name="test-grouping-2">
+ <refine target-node="test-choice-2">
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ </refine>
+ <refine target-node="test-anyxml-2">
+ <config value="false"></config>
+ <mandatory value="false"></mandatory>
+ </refine>
+ </uses>
+ </notification>
+</module>
\ No newline at end of file