Merge "Switch to using plexus-build-api for file output"
[mdsal.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 Constructor<?> assertContainsConstructor(Class<?> clazz, Class<?>... args) {
145         try {
146             return 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      * @return method with given name, return type and parameter types
166      */
167     static Method assertContainsMethod(Class<?> clazz, Class<?> returnType, String name, Class<?>... args) {
168         try {
169             Method m = clazz.getDeclaredMethod(name, args);
170             assertEquals(returnType, m.getReturnType());
171             return m;
172         } catch (NoSuchMethodException e) {
173             throw new AssertionError("Method " + name + " with args " + Arrays.toString(args)
174                     + " does not exists in class " + clazz.getSimpleName());
175         }
176     }
177
178     /**
179      * Asserts that class contains method with given name and return type.
180      *
181      * @param clazz
182      *            class to test
183      * @param returnTypeStr
184      *            name of method return type
185      * @param name
186      *            method name
187      * @param loader
188      *            current class loader
189      */
190     static void assertContainsMethod(Class<?> clazz, String returnTypeStr, String name, ClassLoader loader) {
191         Class<?> returnType;
192         try {
193             returnType = Class.forName(returnTypeStr, true, loader);
194             Method method = clazz.getMethod(name);
195             assertEquals(returnType, method.getReturnType());
196         } catch (ClassNotFoundException e) {
197             throw new AssertionError("Return type of method '" + name + "' not found");
198         } catch (NoSuchMethodException e) {
199             throw new AssertionError("Method " + name + " does not exists in class " + clazz.getSimpleName());
200         }
201     }
202
203     /**
204      * Asserts that class containes hashCode, equals and toString methods.
205      *
206      * @param clazz
207      *            class to test
208      */
209     static void assertContainsDefaultMethods(Class<?> clazz) {
210         assertContainsMethod(clazz, Integer.TYPE, "hashCode");
211         assertContainsMethod(clazz, Boolean.TYPE, "equals", Object.class);
212         assertContainsMethod(clazz, String.class, "toString");
213     }
214
215     /**
216      * Asserts that class contains 'public static
217      * java.util.List<com.google.common.collect.Range<java.lang.Integer>>
218      * getLength()' method.
219      *
220      * @param clazz
221      *            class to test
222      */
223     static void assertContainsGetLength(Class<?> clazz) {
224         try {
225             Method m = clazz.getDeclaredMethod("getLength");
226             java.lang.reflect.Type returnType = m.getGenericReturnType();
227             assertTrue("Return type of getLength method must be ParameterizedType",
228                     returnType instanceof ParameterizedType);
229             ParameterizedType listType = (ParameterizedType) returnType;
230             assertEquals("interface java.util.List", listType.getRawType().toString());
231
232             java.lang.reflect.Type[] args = listType.getActualTypeArguments();
233             assertEquals(1, args.length);
234             java.lang.reflect.Type range = args[0];
235             assertTrue(range instanceof ParameterizedType);
236             ParameterizedType pRange = (ParameterizedType) range;
237             assertEquals("class com.google.common.collect.Range", pRange.getRawType().toString());
238
239             args = pRange.getActualTypeArguments();
240             assertEquals(1, args.length);
241             java.lang.reflect.Type integer = args[0];
242             assertEquals("class java.lang.Integer", integer.toString());
243         } catch (NoSuchMethodException e) {
244             throw new AssertionError("Method getLength does not exists in class " + clazz.getSimpleName());
245         }
246     }
247
248     /**
249      * Asserts that class implements given interface.
250      *
251      * @param clazz
252      *            source to test
253      * @param ifc
254      *            expected interface
255      */
256     static void assertImplementsIfc(Class<?> clazz, Class<?> ifc) {
257         Class<?>[] interfaces = clazz.getInterfaces();
258         List<Class<?>> ifcsList = Arrays.asList(interfaces);
259         if (!ifcsList.contains(ifc)) {
260             throw new AssertionError(clazz + " should implement " + ifc);
261         }
262     }
263
264     /**
265      * Test if interface generated from augment extends Augmentation interface
266      * with correct generic type.
267      *
268      * @param clazz
269      *            interface generated from augment
270      * @param genericTypeName
271      *            fully qualified name of expected parameter type
272      */
273     static void testAugmentation(Class<?> clazz, String genericTypeName) {
274         final String ifcName = "interface org.opendaylight.yangtools.yang.binding.Augmentation";
275         assertImplementsParameterizedIfc(clazz, ifcName, genericTypeName);
276     }
277
278     /**
279      * Asserts that class implements interface with given name and generic type
280      * parameter.
281      *
282      * @param clazz
283      *            class to test
284      * @param ifcName
285      *            name of interface
286      * @param genericTypeName
287      *            name of generic type
288      */
289     static void assertImplementsParameterizedIfc(Class<?> clazz, String ifcName, String genericTypeName) {
290         ParameterizedType ifcType = null;
291         for (java.lang.reflect.Type ifc : clazz.getGenericInterfaces()) {
292             if (ifc instanceof ParameterizedType) {
293                 ParameterizedType pt = (ParameterizedType) ifc;
294                 if (ifcName.equals(pt.getRawType().toString())) {
295                     ifcType = pt;
296                 }
297             }
298         }
299         assertNotNull(ifcType);
300
301         java.lang.reflect.Type[] typeArguments = ifcType.getActualTypeArguments();
302         assertEquals(1, typeArguments.length);
303         assertEquals("interface " + genericTypeName, typeArguments[0].toString());
304     }
305
306     /**
307      * Test if source code is compilable.
308      *
309      * @param sourcesOutputDir
310      *            directory containing source files
311      * @param compiledOutputDir
312      *            compiler output directory
313      */
314     static void testCompilation(File sourcesOutputDir, File compiledOutputDir) {
315         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
316         StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
317         List<File> filesList = getJavaFiles(sourcesOutputDir);
318         Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
319         Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
320         boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
321         assertTrue(compiled);
322     }
323
324     /**
325      * Asserts that directory contains exactly given count of files.
326      *
327      * @param dir
328      *            directory to test
329      * @param count
330      *            expected count of files in directory
331      */
332     static void assertFilesCount(File dir, int count) {
333         File[] dirContent = dir.listFiles();
334         if (dirContent == null) {
335             throw new AssertionError("File " + dir + " doesn't exists or it's not a directory");
336         } else {
337             assertEquals("Unexpected count of generated files", count, dirContent.length);
338         }
339     }
340
341     /**
342      * Search recursively given directory for *.java files.
343      *
344      * @param directory
345      *            directory to search
346      * @return List of java files found
347      */
348     private static List<File> getJavaFiles(File directory) {
349         List<File> result = new ArrayList<>();
350         File[] filesToRead = directory.listFiles();
351         if (filesToRead != null) {
352             for (File file : filesToRead) {
353                 if (file.isDirectory()) {
354                     result.addAll(getJavaFiles(file));
355                 } else {
356                     String absPath = file.getAbsolutePath();
357                     if (absPath.endsWith(".java")) {
358                         result.add(file);
359                     }
360                 }
361             }
362         }
363         return result;
364     }
365
366     static List<File> getSourceFiles(String path) throws FileNotFoundException {
367         final String resPath = BaseCompilationTest.class.getResource(path).getPath();
368         final File sourcesDir = new File(resPath);
369         if (sourcesDir.exists()) {
370             final List<File> sourceFiles = new ArrayList<>();
371             final File[] fileArray = sourcesDir.listFiles();
372             if (fileArray == null) {
373                 throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
374             }
375             sourceFiles.addAll(Arrays.asList(fileArray));
376             return sourceFiles;
377         } else {
378             throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
379         }
380     }
381
382     static void deleteTestDir(File file) {
383         if (file.isDirectory()) {
384             File[] filesToDelete = file.listFiles();
385             if (filesToDelete != null) {
386                 for (File f : filesToDelete) {
387                     deleteTestDir(f);
388                 }
389             }
390         }
391         if (!file.delete()) {
392             throw new RuntimeException("Failed to clean up after test");
393         }
394     }
395
396 }