2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.sal.java.api.generator.test;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
14 import java.io.FileNotFoundException;
15 import java.lang.annotation.Annotation;
16 import java.lang.reflect.Method;
18 import java.net.URLClassLoader;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashSet;
22 import java.util.List;
25 import javax.tools.JavaCompiler;
26 import javax.tools.JavaFileObject;
27 import javax.tools.StandardJavaFileManager;
28 import javax.tools.ToolProvider;
30 import org.junit.Before;
31 import org.junit.BeforeClass;
32 import org.junit.Test;
33 import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator;
34 import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl;
35 import org.opendaylight.yangtools.sal.binding.model.api.Type;
36 import org.opendaylight.yangtools.sal.java.api.generator.GeneratorJavaFile;
37 import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
38 import org.opendaylight.yangtools.yang.model.api.Module;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
43 * Test correct code generation.
46 public class CompilationTest {
47 private static final String FS = File.separator;
48 private static final String NS_TEST = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1" + FS
49 + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
50 private static final String NS_FOO = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1" + FS
51 + "urn" + FS + "opendaylight" + FS + "foo" + FS + "rev131008";
53 private static final String TEST_PATH = "target" + FS + "test";
54 private static final File TEST_DIR = new File(TEST_PATH);
56 private static final String GENERATOR_OUTPUT_PATH = TEST_PATH + FS + "src";
57 private static final File GENERATOR_OUTPUT_DIR = new File(GENERATOR_OUTPUT_PATH);
58 private static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
59 private static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
61 private YangParserImpl parser;
62 private BindingGenerator bindingGenerator;
65 public static void createTestDirs() {
66 if (TEST_DIR.exists()) {
67 deleteTestDir(TEST_DIR);
69 assertTrue(GENERATOR_OUTPUT_DIR.mkdirs());
70 assertTrue(COMPILER_OUTPUT_DIR.mkdirs());
75 parser = new YangParserImpl();
76 bindingGenerator = new BindingGeneratorImpl();
80 * Method to clean resources. It is manually called at the end of each test
81 * instead of marking it with @After annotation to prevent removing
82 * generated code if test fails.
84 public void cleanUp(File... resourceDirs) {
85 for (File resourceDir : resourceDirs) {
86 if (resourceDir.exists()) {
87 deleteTestDir(resourceDir);
93 public void testListGeneration() throws Exception {
94 final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "list-gen");
95 assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
96 final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "list-gen");
97 assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
99 final List<File> sourceFiles = getSourceFiles("/compilation/list-gen");
100 final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
101 final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
102 final List<Type> types = bindingGenerator.generateTypes(context);
103 final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
104 generator.generateToFile(sourcesOutputDir);
106 // Test if all sources are generated
107 File parent = new File(sourcesOutputDir, NS_TEST);
108 File linksKeyFile = new File(parent, "LinksKey.java");
109 assertTrue(new File(parent, "KeyArgs.java").exists());
110 assertTrue(new File(parent, "Links.java").exists());
111 assertTrue(new File(parent, "LinksBuilder.java").exists());
112 assertTrue(linksKeyFile.exists());
113 assertTrue(new File(parent, "TestData.java").exists());
114 assertTrue(new File(parent, "links" + FS + "Level.java").exists());
115 assertTrue(new File(parent, "links" + FS + "LinkGroup.java").exists());
116 assertTrue(new File(parent, "links" + FS + "Node.java").exists());
117 assertTrue(new File(parent, "links" + FS + "NodeBuilder.java").exists());
118 assertTrue(new File(parent, "links" + FS + "NodeList.java").exists());
119 assertTrue(new File(parent, "links" + FS + "NodeListBuilder.java").exists());
120 assertTrue(linksKeyFile.exists());
122 // Test if sources are compilable
123 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
124 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
125 List<File> filesList = getJavaFiles(sourcesOutputDir);
126 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
127 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
128 boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
129 assertTrue(compiled);
131 ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
132 Class<?> linksKeyClass = Class.forName("org.opendaylight.yang.gen.v1.urn.opendaylight.test.rev131008.LinksKey",
135 // Test list key constructor arguments ordering
137 linksKeyClass.getConstructor(Byte.class, String.class, Integer.class);
138 } catch (NoSuchMethodException e) {
139 throw new AssertionError("Parameters of list key constructor are not properly ordered");
142 cleanUp(sourcesOutputDir, compiledOutputDir);
146 public void testAugmentUnderUsesGeneration() throws Exception {
147 final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "augment-under-uses");
148 assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
149 final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "augment-under-uses");
150 assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
152 final List<File> sourceFiles = getSourceFiles("/compilation/augment-under-uses");
153 final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
154 final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
155 final List<Type> types = bindingGenerator.generateTypes(context);
156 final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
157 generator.generateToFile(sourcesOutputDir);
159 // Test if all sources are generated
160 File parent = new File(sourcesOutputDir, NS_TEST);
161 assertTrue(new File(parent, "Object.java").exists());
162 assertTrue(new File(parent, "OpenObject.java").exists());
163 assertTrue(new File(parent, "object" + FS + "Nodes.java").exists());
164 assertTrue(new File(parent, "object" + FS + "NodesBuilder.java").exists());
165 assertTrue(new File(parent, "open" + FS + "object" + FS + "Nodes1.java").exists());
166 assertTrue(new File(parent, "open" + FS + "object" + FS + "Nodes1Builder.java").exists());
167 assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "Links.java").exists());
168 assertTrue(new File(parent, "open" + FS + "object" + FS + "nodes" + FS + "LinksBuilder.java").exists());
170 // Test if sources are compilable
171 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
172 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
174 List<File> filesList = getJavaFiles(sourcesOutputDir);
175 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
176 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
177 boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
178 assertTrue(compiled);
180 cleanUp(sourcesOutputDir, compiledOutputDir);
183 // TODO: add test for return types, equals and hashcode
185 public void testLeafReturnTypes() throws Exception {
186 final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "leaf-return-types");
187 assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
188 final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "leaf-return-types");
189 assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
191 final List<File> sourceFiles = getSourceFiles("/compilation/leaf-return-types");
192 final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
193 final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
194 final List<Type> types = bindingGenerator.generateTypes(context);
195 final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
196 generator.generateToFile(sourcesOutputDir);
198 File parent = new File(sourcesOutputDir, NS_TEST);
199 assertTrue(new File(parent, "TestData.java").exists());
200 assertTrue(new File(parent, "Nodes.java").exists());
201 assertTrue(new File(parent, "NodesBuilder.java").exists());
202 assertTrue(new File(parent, "Alg.java").exists());
204 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
205 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
207 List<File> filesList = getJavaFiles(sourcesOutputDir);
208 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
209 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
210 boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
211 assertTrue(compiled);
213 cleanUp(sourcesOutputDir, compiledOutputDir);
217 public void testGenerationContextReferenceExtension() throws Exception {
218 final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "context-reference");
219 assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
220 final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "context-reference");
221 assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
223 final List<File> sourceFiles = getSourceFiles("/compilation/context-reference");
224 final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
225 final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
226 final List<Type> types = bindingGenerator.generateTypes(context);
227 final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
228 generator.generateToFile(sourcesOutputDir);
230 // Test if all sources are generated
231 File fooParent = new File(sourcesOutputDir, NS_FOO);
232 File nodes = new File(fooParent, "Nodes.java");
233 File nodesBuilder = new File(fooParent, "NodesBuilder.java");
234 assertTrue(new File(fooParent, "FooData.java").exists());
235 assertTrue(nodes.exists());
236 assertTrue(nodesBuilder.exists());
238 // Test if sources are compilable
239 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
240 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
242 List<File> filesList = getJavaFiles(sourcesOutputDir);
243 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
244 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
245 boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
246 assertTrue(compiled);
248 ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
249 Class<?> nodesClass = Class.forName("org.opendaylight.yang.gen.v1.urn.opendaylight.foo.rev131008.Nodes", true,
254 Method getId = nodesClass.getMethod("getId");
255 Annotation[] annotations = getId.getAnnotations();
256 assertEquals(1, annotations.length);
257 Annotation routingContext = annotations[0];
258 assertEquals(RoutingContext.class, routingContext.annotationType());
259 } catch (NoSuchMethodException e) {
260 throw new AssertionError("Method getId() not found");
263 cleanUp(sourcesOutputDir, compiledOutputDir);
267 public void compilationTest() throws Exception {
268 final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "yang");
269 assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdir());
270 final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "yang");
271 assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdir());
273 final List<File> sourceFiles = getSourceFiles("/yang");
274 final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
275 final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
276 final List<Type> types = bindingGenerator.generateTypes(context);
277 final GeneratorJavaFile generator = new GeneratorJavaFile(new HashSet<>(types));
278 generator.generateToFile(sourcesOutputDir);
280 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
281 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
283 List<File> filesList = getJavaFiles(sourcesOutputDir);
284 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
285 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
286 boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
287 assertTrue(compiled);
289 cleanUp(sourcesOutputDir, compiledOutputDir);
292 private List<File> getSourceFiles(String path) throws FileNotFoundException {
293 final String resPath = getClass().getResource(path).getPath();
294 final File sourcesDir = new File(resPath);
295 if (sourcesDir.exists()) {
296 final List<File> sourceFiles = new ArrayList<>();
297 final File[] fileArray = sourcesDir.listFiles();
298 if (fileArray == null) {
299 throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
301 sourceFiles.addAll(Arrays.asList(fileArray));
304 throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
308 private static void deleteTestDir(File file) {
309 if (file.isDirectory()) {
310 File[] filesToDelete = file.listFiles();
311 if (filesToDelete != null) {
312 for (File f : filesToDelete) {
317 if (!file.delete()) {
318 throw new RuntimeException("Failed to clean up after test");
323 * Search recursively given directory for *.java files.
326 * directory to search
327 * @return List of java files found
329 private List<File> getJavaFiles(File directory) {
330 List<File> result = new ArrayList<>();
331 File[] filesToRead = directory.listFiles();
332 if (filesToRead != null) {
333 for (File file : filesToRead) {
334 if (file.isDirectory()) {
335 result.addAll(getJavaFiles(file));
337 String absPath = file.getAbsolutePath();
338 if (absPath.endsWith(".java")) {