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