Merge "Added export of augmentation schemas to Binding Context"
[yangtools.git] / code-generator / binding-java-api-generator / src / test / java / org / opendaylight / yangtools / sal / java / api / generator / test / CompilationTestUtils.java
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.yangtools.sal.java.api.generator.test;
9
10 import static org.junit.Assert.*;
11
12 import java.io.File;
13 import java.io.FileNotFoundException;
14 import java.lang.reflect.Constructor;
15 import java.lang.reflect.Field;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.ParameterizedType;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.List;
21
22 import javax.tools.JavaCompiler;
23 import javax.tools.JavaFileObject;
24 import javax.tools.StandardJavaFileManager;
25 import javax.tools.ToolProvider;
26
27 public class CompilationTestUtils {
28     public static final String FS = File.separator;
29     static final String BASE_PKG = "org.opendaylight.yang.gen.v1";
30
31     static final String TEST_PATH = "target" + FS + "test";
32     static final File TEST_DIR = new File(TEST_PATH);
33
34     static final String GENERATOR_OUTPUT_PATH = TEST_PATH + FS + "src";
35     static final File GENERATOR_OUTPUT_DIR = new File(GENERATOR_OUTPUT_PATH);
36     static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
37     static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
38
39     static final String BASE_PATH = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1";
40     static final String NS_TEST = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
41     static final String NS_FOO = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "foo" + FS + "rev131008";
42     static final String NS_BAR = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "bar" + FS + "rev131008";
43     static final String NS_BAZ = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "baz" + FS + "rev131008";
44
45     /**
46      * Method to clean resources. It is manually called at the end of each test
47      * instead of marking it with @After annotation to prevent removing
48      * generated code if test fails.
49      */
50     static void cleanUp(File... resourceDirs) {
51         for (File resourceDir : resourceDirs) {
52             if (resourceDir.exists()) {
53                 deleteTestDir(resourceDir);
54             }
55         }
56     }
57
58     /**
59      * Asserts that class contains field with fiven name and type.
60      *
61      * @param clazz
62      *            class to test
63      * @param name
64      *            field name
65      * @param type
66      *            field type
67      * @return field with given name if present in class
68      */
69     static Field assertContainsField(Class<?> clazz, String name, Class<?> type) {
70         try {
71             Field f = clazz.getDeclaredField(name);
72             assertEquals(type, f.getType());
73             return f;
74         } catch (NoSuchFieldException e) {
75             throw new AssertionError("Field " + name + " does not exists in class " + clazz.getSimpleName());
76         }
77     }
78
79     /**
80      * Asserts that class contains field with given name and value. Method tries
81      * to create new instance of class and get value of field. If class
82      * constructor contains any arguments, class is instantiated with null
83      * values.
84      *
85      * @param clazz
86      *            class to test
87      * @param name
88      *            name of field
89      * @param returnType
90      *            return type of field
91      * @param expectedValue
92      *            expected value of field
93      * @param constructorArgs
94      *            constructor arguments of class to test
95      */
96     static void assertContainsFieldWithValue(Class<?> clazz, String name, Class<?> returnType, Object expectedValue,
97             Class<?>... constructorArgs) {
98         Object[] initargs = null;
99         if (constructorArgs != null && constructorArgs.length > 0) {
100             initargs = new Object[constructorArgs.length];
101             for (int i = 0; i < constructorArgs.length; i++) {
102                 initargs[i] = null;
103             }
104         }
105         assertContainsFieldWithValue(clazz, name, returnType, expectedValue, constructorArgs, initargs);
106     }
107
108     /**
109      * Asserts that class contains field with given name, return type and value.
110      *
111      * @param clazz
112      *            class to test
113      * @param name
114      *            name of field
115      * @param returnType
116      *            return type of field
117      * @param expectedValue
118      *            expected value of field
119      * @param constructorArgs
120      *            array of constructor arguments classes
121      * @param initargs
122      *            array of constructor values
123      */
124     static void assertContainsFieldWithValue(Class<?> clazz, String name, Class<?> returnType, Object expectedValue,
125             Class<?>[] constructorArgs, Object... initargs) {
126         Field f = assertContainsField(clazz, name, returnType);
127         try {
128             Constructor<?> c = clazz.getDeclaredConstructor(constructorArgs);
129             Object o = c.newInstance(initargs);
130             assertEquals(expectedValue, f.get(o));
131         } catch (Exception e) {
132             throw new AssertionError("Failed to perform " + name + " field test", e);
133         }
134     }
135
136     /**
137      * Asserts that class contains constructor with parameter types.
138      *
139      * @param clazz
140      *            class to test
141      * @param args
142      *            array of argument classes
143      */
144     static void assertContainsConstructor(Class<?> clazz, Class<?>... args) {
145         try {
146             clazz.getDeclaredConstructor(args);
147         } catch (NoSuchMethodException e) {
148             throw new AssertionError("Constructor with args " + Arrays.toString(args) + " does not exists in class "
149                     + clazz.getSimpleName());
150         }
151     }
152
153     /**
154      * Asserts that class contains method with given name, return type and
155      * parameter types.
156      *
157      * @param clazz
158      *            class to test
159      * @param returnType
160      *            method return type
161      * @param name
162      *            method name
163      * @param args
164      *            array of parameter type classes
165      */
166     static void assertContainsMethod(Class<?> clazz, Class<?> returnType, String name, Class<?>... args) {
167         try {
168             Method m = clazz.getDeclaredMethod(name, args);
169             assertEquals(returnType, m.getReturnType());
170         } catch (NoSuchMethodException e) {
171             throw new AssertionError("Method " + name + " with args " + Arrays.toString(args)
172                     + " does not exists in class " + clazz.getSimpleName());
173         }
174     }
175
176     /**
177      * Asserts that class contains method with given name and return type.
178      *
179      * @param clazz
180      *            class to test
181      * @param returnTypeStr
182      *            name of method return type
183      * @param name
184      *            method name
185      * @param loader
186      *            current class loader
187      */
188     static void assertContainsMethod(Class<?> clazz, String returnTypeStr, String name, ClassLoader loader) {
189         Class<?> returnType;
190         try {
191             returnType = Class.forName(returnTypeStr, true, loader);
192             Method method = clazz.getMethod(name);
193             assertEquals(returnType, method.getReturnType());
194         } catch (ClassNotFoundException e) {
195             throw new AssertionError("Return type of method '" + name + "' not found");
196         } catch (NoSuchMethodException e) {
197             throw new AssertionError("Method " + name + " does not exists in class " + clazz.getSimpleName());
198         }
199     }
200
201     /**
202      * Asserts that class containes hashCode, equals and toString methods.
203      *
204      * @param clazz
205      *            class to test
206      */
207     static void assertContainsDefaultMethods(Class<?> clazz) {
208         assertContainsMethod(clazz, Integer.TYPE, "hashCode");
209         assertContainsMethod(clazz, Boolean.TYPE, "equals", Object.class);
210         assertContainsMethod(clazz, String.class, "toString");
211     }
212
213     /**
214      * Asserts that class contains 'public static
215      * java.util.List<com.google.common.collect.Range<java.lang.Integer>>
216      * getLength()' method.
217      *
218      * @param clazz
219      *            class to test
220      */
221     static void assertContainsGetLength(Class<?> clazz) {
222         try {
223             Method m = clazz.getDeclaredMethod("getLength");
224             java.lang.reflect.Type returnType = m.getGenericReturnType();
225             assertTrue("Return type of getLength method must be ParameterizedType",
226                     returnType instanceof ParameterizedType);
227             ParameterizedType listType = (ParameterizedType) returnType;
228             assertEquals("interface java.util.List", listType.getRawType().toString());
229
230             java.lang.reflect.Type[] args = listType.getActualTypeArguments();
231             assertEquals(1, args.length);
232             java.lang.reflect.Type range = args[0];
233             assertTrue(range instanceof ParameterizedType);
234             ParameterizedType pRange = (ParameterizedType) range;
235             assertEquals("class com.google.common.collect.Range", pRange.getRawType().toString());
236
237             args = pRange.getActualTypeArguments();
238             assertEquals(1, args.length);
239             java.lang.reflect.Type integer = args[0];
240             assertEquals("class java.lang.Integer", integer.toString());
241         } catch (NoSuchMethodException e) {
242             throw new AssertionError("Method getLength does not exists in class " + clazz.getSimpleName());
243         }
244     }
245
246     /**
247      * Asserts that class implements given interface.
248      *
249      * @param clazz
250      *            source to test
251      * @param ifc
252      *            expected interface
253      */
254     static void assertImplementsIfc(Class<?> clazz, Class<?> ifc) {
255         Class<?>[] interfaces = clazz.getInterfaces();
256         List<Class<?>> ifcsList = Arrays.asList(interfaces);
257         if (!ifcsList.contains(ifc)) {
258             throw new AssertionError(clazz + " should implement " + ifc);
259         }
260     }
261
262     /**
263      * Test if interface generated from augment extends Augmentation interface
264      * with correct generic type.
265      *
266      * @param clazz
267      *            interface generated from augment
268      * @param genericTypeName
269      *            fully qualified name of expected parameter type
270      */
271     static void testAugmentation(Class<?> clazz, String genericTypeName) {
272         final String ifcName = "interface org.opendaylight.yangtools.yang.binding.Augmentation";
273         assertImplementsParameterizedIfc(clazz, ifcName, genericTypeName);
274     }
275
276     /**
277      * Asserts that class implements interface with given name and generic type
278      * parameter.
279      *
280      * @param clazz
281      *            class to test
282      * @param ifcName
283      *            name of interface
284      * @param genericTypeName
285      *            name of generic type
286      */
287     static void assertImplementsParameterizedIfc(Class<?> clazz, String ifcName, String genericTypeName) {
288         ParameterizedType ifcType = null;
289         for (java.lang.reflect.Type ifc : clazz.getGenericInterfaces()) {
290             if (ifc instanceof ParameterizedType) {
291                 ParameterizedType pt = (ParameterizedType) ifc;
292                 if (ifcName.equals(pt.getRawType().toString())) {
293                     ifcType = pt;
294                 }
295             }
296         }
297         assertNotNull(ifcType);
298
299         java.lang.reflect.Type[] typeArguments = ifcType.getActualTypeArguments();
300         assertEquals(1, typeArguments.length);
301         assertEquals("interface " + genericTypeName, typeArguments[0].toString());
302     }
303
304     /**
305      * Test if source code is compilable.
306      *
307      * @param sourcesOutputDir
308      *            directory containing source files
309      * @param compiledOutputDir
310      *            compiler output directory
311      */
312     static void testCompilation(File sourcesOutputDir, File compiledOutputDir) {
313         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
314         StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
315         List<File> filesList = getJavaFiles(sourcesOutputDir);
316         Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
317         Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
318         boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
319         assertTrue(compiled);
320     }
321
322     /**
323      * Asserts that directory contains exactly given count of files.
324      *
325      * @param dir
326      *            directory to test
327      * @param count
328      *            expected count of files in directory
329      */
330     static void assertFilesCount(File dir, int count) {
331         File[] dirContent = dir.listFiles();
332         if (dirContent == null) {
333             throw new AssertionError("File " + dir + " doesn't exists or it's not a directory");
334         } else {
335             assertEquals("Unexpected count of generated files", count, dirContent.length);
336         }
337     }
338
339     /**
340      * Search recursively given directory for *.java files.
341      *
342      * @param directory
343      *            directory to search
344      * @return List of java files found
345      */
346     private static List<File> getJavaFiles(File directory) {
347         List<File> result = new ArrayList<>();
348         File[] filesToRead = directory.listFiles();
349         if (filesToRead != null) {
350             for (File file : filesToRead) {
351                 if (file.isDirectory()) {
352                     result.addAll(getJavaFiles(file));
353                 } else {
354                     String absPath = file.getAbsolutePath();
355                     if (absPath.endsWith(".java")) {
356                         result.add(file);
357                     }
358                 }
359             }
360         }
361         return result;
362     }
363
364     static List<File> getSourceFiles(String path) throws FileNotFoundException {
365         final String resPath = BaseCompilationTest.class.getResource(path).getPath();
366         final File sourcesDir = new File(resPath);
367         if (sourcesDir.exists()) {
368             final List<File> sourceFiles = new ArrayList<>();
369             final File[] fileArray = sourcesDir.listFiles();
370             if (fileArray == null) {
371                 throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
372             }
373             sourceFiles.addAll(Arrays.asList(fileArray));
374             return sourceFiles;
375         } else {
376             throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
377         }
378     }
379
380     static void deleteTestDir(File file) {
381         if (file.isDirectory()) {
382             File[] filesToDelete = file.listFiles();
383             if (filesToDelete != null) {
384                 for (File f : filesToDelete) {
385                     deleteTestDir(f);
386                 }
387             }
388         }
389         if (!file.delete()) {
390             throw new RuntimeException("Failed to clean up after test");
391         }
392     }
393
394 }