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