From: Tony Tkacik Date: Wed, 9 Oct 2013 11:13:47 +0000 (+0000) Subject: Merge "Added generated code compilation test." X-Git-Tag: third-party-0.1.2~12 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=7bd76c39f31c9eedd845d9a4fc59d08df177160f;hp=c2ddb68b848a35b86c097d128a343414e18bdaff;p=yangtools.git Merge "Added generated code compilation test." --- diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend index 2adf3914f9..69c9e163aa 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend @@ -774,7 +774,8 @@ public class BindingGeneratorImpl implements BindingGenerator { checkArgument(module !== null, "Module parameter can not be null"); val List genTypes = new ArrayList(); val basePackageName = moduleNamespaceToPackageName(module); - val Set groupings = module.groupings; + val it = new DataNodeIterator(module); + val List groupings = it.allGroupings(); val List groupingsSortedByDependencies = new GroupingDefinitionDependencySort().sort( groupings); diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTest.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTest.java new file mode 100644 index 0000000000..06d09b1873 --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/CompilationTest.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2013 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.sal.java.api.generator.test; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator; +import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl; +import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; + +/** + * Test correct code generation. + * + */ +public class CompilationTest { + private static final String FS = File.separator; + private static final String TEST_PATH = "target" + FS + "test"; + private static final File TEST_DIR = new File(TEST_PATH); + + private static final String GENERATOR_OUTPUT_PATH = TEST_PATH + FS + "src"; + private static final File GENERATOR_OUTPUT_DIR = new File(GENERATOR_OUTPUT_PATH); + private static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin"; + private static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH); + + private YangParserImpl parser; + private BindingGenerator bindingGenerator; + + @BeforeClass + public static void createTestDirs() { + if (TEST_DIR.exists()) { + deleteTestDir(TEST_DIR); + } + assertTrue(GENERATOR_OUTPUT_DIR.mkdirs()); + assertTrue(COMPILER_OUTPUT_DIR.mkdirs()); + } + + @Before + public void init() { + parser = new YangParserImpl(); + bindingGenerator = new BindingGeneratorImpl(); + } + + /** + * Method to clean resources. It is manually called at the end of each test + * instead of marking it with @After annotation to prevent removing + * generated code if test fails. + */ + public void cleanUp(File... resourceDirs) { + for (File resourceDir : resourceDirs) { + if (resourceDir.exists()) { + deleteTestDir(resourceDir); + } + } + } + + @Test + public void testListGeneration() throws Exception { + final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "list-gen"); + assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir()); + final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "list-gen"); + assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir()); + + final List sourceFiles = getSourceFiles("/compilation/list-gen"); + final Set modulesToBuild = parser.parseYangModels(sourceFiles); + final SchemaContext context = parser.resolveSchemaContext(modulesToBuild); + final List types = bindingGenerator.generateTypes(context); + final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types)); + generator.generateToFile(sourcesOutputDir); + + File parent = new File(sourcesOutputDir, "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1" + + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008"); + File linksKeyFile = new File(parent, "LinksKey.java"); + assertTrue(new File(parent, "KeyArgs.java").exists()); + assertTrue(new File(parent, "Links.java").exists()); + assertTrue(new File(parent, "LinksBuilder.java").exists()); + assertTrue(linksKeyFile.exists()); + assertTrue(new File(parent, "TestData.java").exists()); + assertTrue(new File(parent, "links" + FS + "Level.java").exists()); + assertTrue(new File(parent, "links" + FS + "LinkGroup.java").exists()); + assertTrue(new File(parent, "links" + FS + "Node.java").exists()); + assertTrue(new File(parent, "links" + FS + "NodeBuilder.java").exists()); + assertTrue(new File(parent, "links" + FS + "NodeList.java").exists()); + assertTrue(new File(parent, "links" + FS + "NodeListBuilder.java").exists()); + assertTrue(linksKeyFile.exists()); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); + + List filesList = getJavaFiles(sourcesOutputDir); + Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList); + Iterable options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath()); + boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call(); + assertTrue(compiled); + + ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() }); + Class linksKeyClass = Class.forName("org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.LinksKey", + true, loader); + + // test list key constructor arguments ordering + try { + linksKeyClass.getConstructor(Byte.class, String.class, Integer.class); + } catch (NoSuchMethodException e) { + throw new AssertionError("Parameters of list key constructor are not properly ordered"); + } + + cleanUp(sourcesOutputDir, compiledOutputDir); + } + + @Test + public void testAugmentUnderUsesGeneration() throws Exception { + final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "augment-under-uses"); + assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir()); + final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "augment-under-uses"); + assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir()); + + final List sourceFiles = getSourceFiles("/compilation/augment-under-uses"); + final Set modulesToBuild = parser.parseYangModels(sourceFiles); + final SchemaContext context = parser.resolveSchemaContext(modulesToBuild); + final List types = bindingGenerator.generateTypes(context); + final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types)); + generator.generateToFile(sourcesOutputDir); + + File parent = new File(sourcesOutputDir + FS + "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + + "v1" + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008"); + assertTrue(new File(parent, "Object.java").exists()); + assertTrue(new File(parent, "OpenObject.java").exists()); + assertTrue(new File(parent, "object" + FS + "Nodes.java").exists()); + assertTrue(new File(parent, "object" + FS + "NodesBuilder.java").exists()); + assertTrue(new File(parent, "open" + FS + "object" + FS + "Nodes1.java").exists()); + assertTrue(new File(parent, "open" + FS + "object" + FS + "Nodes1Builder.java").exists()); + assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "Links.java").exists()); + assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "LinksBuilder.java").exists()); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); + + List filesList = getJavaFiles(sourcesOutputDir); + Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList); + Iterable options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath()); + boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call(); + assertTrue(compiled); + + cleanUp(sourcesOutputDir, compiledOutputDir); + } + + @Test + public void compilationTest() throws Exception { + final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "yang"); + assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir()); + final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "yang"); + assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir()); + + final List sourceFiles = getSourceFiles("/yang"); + final Set modulesToBuild = parser.parseYangModels(sourceFiles); + final SchemaContext context = parser.resolveSchemaContext(modulesToBuild); + final List types = bindingGenerator.generateTypes(context); + final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types)); + generator.generateToFile(sourcesOutputDir); + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); + + List filesList = getJavaFiles(sourcesOutputDir); + Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList); + Iterable options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath()); + boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call(); + assertTrue(compiled); + } + + private List getSourceFiles(String path) { + final String resPath = getClass().getResource(path).getPath(); + final File sourcesDir = new File(resPath); + final List sourceFiles = new ArrayList<>(); + final File[] fileArray = sourcesDir.listFiles(); + sourceFiles.addAll(Arrays.asList(fileArray)); + return sourceFiles; + } + + private static void deleteTestDir(File file) { + if (file.isDirectory()) { + for (File f : file.listFiles()) { + deleteTestDir(f); + } + } + if (!file.delete()) { + throw new RuntimeException("Failed to clean up after test"); + } + } + + /** + * Search recursively given directory for *.java files. + * + * @param directory + * directory to search + * @return List of java files found + */ + private List getJavaFiles(File directory) { + List result = new ArrayList(); + for (File file : directory.listFiles()) { + if (file.isDirectory()) { + result.addAll(getJavaFiles(file)); + } else { + String absPath = file.getAbsolutePath(); + if (absPath.endsWith(".java")) { + result.add(file); + } + } + } + return result; + } +} diff --git a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/GeneratorJavaFileTest.java b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/GeneratorJavaFileTest.java index 9eea68af90..1b18fe9513 100644 --- a/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/GeneratorJavaFileTest.java +++ b/code-generator/binding-java-api-generator/src/test/java/org/opendaylight/yangtools/sal/java/api/generator/test/GeneratorJavaFileTest.java @@ -41,32 +41,6 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; public class GeneratorJavaFileTest { private static final String FS = File.separator; private static final String PATH = "target/test/test-dir"; - private final File testDir = new File(PATH); - - private static final String GENERATOR_OUTPUT_PATH = "target/test/src"; - private static final File GENERATOR_OUTPUT = new File(GENERATOR_OUTPUT_PATH); - private static final String COMPILER_OUTPUT_PATH = "target/test/bin"; - private static final File COMPILER_OUTPUT = new File(COMPILER_OUTPUT_PATH); - - @Before - public void init() { - assertTrue(testDir.mkdirs()); - assertTrue(COMPILER_OUTPUT.mkdirs()); - assertTrue(GENERATOR_OUTPUT.mkdirs()); - } - - @After - public void cleanUp() { - if (testDir.exists()) { - deleteTestDir(testDir); - } - if (COMPILER_OUTPUT.exists()) { - deleteTestDir(COMPILER_OUTPUT); - } - if (GENERATOR_OUTPUT.exists()) { - deleteTestDir(GENERATOR_OUTPUT); - } - } @Test public void test() throws IOException { @@ -94,73 +68,10 @@ public class GeneratorJavaFileTest { assertTrue(filesList.contains("Type4Builder.java")); } - @Test - public void compilationTest() throws Exception { - final YangParserImpl parser = new YangParserImpl(); - final BindingGenerator bindingGenerator = new BindingGeneratorImpl(); - - final String resPath = getClass().getResource("/yang").getPath(); - final File sourcesDir = new File(resPath); - final List sourceFiles = new ArrayList(); - final File[] fileArray = sourcesDir.listFiles(); - - for (int i = 0; i < fileArray.length; ++i) { - sourceFiles.add(fileArray[i]); - } - - final Set modulesToBuild = parser.parseYangModels(sourceFiles); - - final SchemaContext context = parser.resolveSchemaContext(modulesToBuild); - final List types = bindingGenerator.generateTypes(context); - final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types)); - generator.generateToFile(new File(GENERATOR_OUTPUT_PATH)); - - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); - - List filesList = getJavaFiles(new File(GENERATOR_OUTPUT_PATH)); - Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList); - Iterable options = Arrays.asList(new String[] { "-d", COMPILER_OUTPUT_PATH }); - boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call(); - assertTrue(compiled); - } - private GeneratedType createGeneratedType(String pkgName, String name) { GeneratedTypeBuilder builder = new GeneratedTypeBuilderImpl(pkgName, name); builder.addImplementsType(BindingTypes.DATA_OBJECT); return builder.toInstance(); } - private void deleteTestDir(File file) { - if (file.isDirectory()) { - for (File f : file.listFiles()) { - deleteTestDir(f); - } - } - if (!file.delete()) { - throw new RuntimeException("Failed to clean up after test"); - } - } - - /** - * Search recursively given directory for *.java files. - * - * @param directory - * directory to search - * @return List of java files found - */ - private List getJavaFiles(File directory) { - List result = new ArrayList(); - for (File file : directory.listFiles()) { - if (file.isDirectory()) { - result.addAll(getJavaFiles(file)); - } else { - String absPath = file.getAbsolutePath(); - if (absPath.endsWith(".java")) { - result.add(file); - } - } - } - return result; - } } diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/augment-under-uses/test.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/augment-under-uses/test.yang new file mode 100644 index 0000000000..a13c39e59b --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/resources/compilation/augment-under-uses/test.yang @@ -0,0 +1,26 @@ +module test { + yang-version 1; + namespace "urn:opendaylight:test"; + prefix "t"; + + revision "2013-10-08" { + } + + grouping object { + container nodes { + } + } + + grouping open-object { + uses object { + augment "nodes" { + container links { + leaf id { + type string; + } + } + } + } + } + +} diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/list-gen/test.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/list-gen/test.yang new file mode 100644 index 0000000000..fed4743d8e --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/resources/compilation/list-gen/test.yang @@ -0,0 +1,43 @@ +module test { + yang-version 1; + namespace "urn:opendaylight:test"; + prefix "t"; + + revision "2013-10-08" { + } + + grouping key-args { + leaf id { + type int8; + } + leaf name { + type string; + } + leaf size { + type int32; + } + } + + list links { + uses key-args; + key "size name id"; + + anyxml text; + choice level; + container node; + grouping link-group { + leaf source { + type int8; + } + } + leaf links-id { + type int32; + } + list node-list { + } + typedef nodes-type { + type string; + } + } + +} diff --git a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/GroupingDefinitionDependencySort.java b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/GroupingDefinitionDependencySort.java index 509b69867e..2936e31e26 100644 --- a/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/GroupingDefinitionDependencySort.java +++ b/code-generator/binding-type-provider/src/main/java/org/opendaylight/yangtools/sal/binding/yang/types/GroupingDefinitionDependencySort.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.sal.binding.yang.types; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -31,22 +32,22 @@ public class GroupingDefinitionDependencySort { /** * Sorts set groupingDefinitions according to the mutual * dependencies.
- * + * * Elements of groupingDefinitions are firstly transformed to * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node * Node} interfaces and then are sorted by * {@link org.opendaylight.yangtools.yang.parser.util.TopologicalSort#sort(Set) * sort()} method of TopologicalSort.
*
- * - * + * + * * Definition of dependency relation:
* The first GroupingDefinition object (in this context) * depends on second GroupingDefinition object if the first one * contains in its set of UsesNode (obtained through * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer#getUses() * getUses} method) reference to the second one.
- * + * * @param groupingDefinitions * set of grouping definition which should be sorted according to * mutual dependencies @@ -54,9 +55,9 @@ public class GroupingDefinitionDependencySort { * dependencies * @throws IllegalArgumentException * if groupingDefinitions - * + * */ - public List sort(final Set groupingDefinitions) { + public List sort(final Collection groupingDefinitions) { if (groupingDefinitions == null) { throw new IllegalArgumentException("Set of Type Definitions " + "cannot be NULL!"); } @@ -75,7 +76,7 @@ public class GroupingDefinitionDependencySort { /** * Wraps every grouping definition to node type and adds to every node * information about dependencies. - * + * * The map with mapping from schema path (represents grouping definition) to * node is created. For every created node (next nodeFrom) is for its * wrapped grouping definition passed the set of its uses nodes @@ -83,14 +84,14 @@ public class GroupingDefinitionDependencySort { * nodeTo). This dependency relationship between nodeFrom and all * found nodesTo is modeled with creating of one edge from nodeFrom to * nodeTo. - * - * + * + * * @param groupingDefinitions * set of goruping definition which will be wrapped to nodes - * + * * @return set of nodes where every one contains wrapped grouping definition */ - private Set groupingDefinitionsToNodes(final Set groupingDefinitions) { + private Set groupingDefinitionsToNodes(final Collection groupingDefinitions) { final Map nodeMap = Maps.newHashMap(); final Set resultNodes = Sets.newHashSet(); @@ -125,7 +126,7 @@ public class GroupingDefinitionDependencySort { * container, from uses in groupings inside * container and from uses inside child nodes of the * container. - * + * * @param container * data node container which can contain some uses of grouping * @return set of uses nodes which were find in container. diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/DataNodeIterator.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/DataNodeIterator.java index 6fb90d96cb..518d6d8a89 100644 --- a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/DataNodeIterator.java +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/DataNodeIterator.java @@ -12,7 +12,16 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; public class DataNodeIterator implements Iterator { @@ -21,6 +30,7 @@ public class DataNodeIterator implements Iterator { private final List allContainers; private final List allChoices; private final List allChilds; + private final List allGroupings; public DataNodeIterator(final DataNodeContainer container) { if (container == null) { @@ -31,6 +41,7 @@ public class DataNodeIterator implements Iterator { this.allLists = new ArrayList<>(); this.allChilds = new ArrayList<>(); this.allChoices = new ArrayList<>(); + this.allGroupings = new ArrayList<>(); this.container = container; traverse(this.container); @@ -48,6 +59,10 @@ public class DataNodeIterator implements Iterator { return allChoices; } + public List allGroupings() { + return allGroupings; + } + private void traverse(final DataNodeContainer dataNode) { if (dataNode == null) { return; @@ -114,6 +129,7 @@ public class DataNodeIterator implements Iterator { final Set groupings = dataNode.getGroupings(); if (groupings != null) { for (GroupingDefinition grouping : groupings) { + allGroupings.add(grouping); traverse(grouping); } }