BUG-1485: remove holder for deprecated Class ranges
[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.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 contains 'public static
283      * java.util.List<com.google.common.collect.Range<java.lang.Integer>>
284      * getLength()' method.
285      *
286      * @param clazz
287      *            class to test
288      */
289     static void assertContainsGetLengthOrRange(final Class<?> clazz, final boolean isLength) {
290         try {
291             Method m = clazz.getDeclaredMethod(isLength ? "length" : "range");
292             java.lang.reflect.Type returnType = m.getGenericReturnType();
293             assertTrue("Return type of getLength method must be ParameterizedType",
294                     returnType instanceof ParameterizedType);
295             ParameterizedType listType = (ParameterizedType) returnType;
296             assertEquals("interface java.util.List", listType.getRawType().toString());
297
298             java.lang.reflect.Type[] args = listType.getActualTypeArguments();
299             assertEquals(1, args.length);
300             java.lang.reflect.Type range = args[0];
301             assertTrue(range instanceof ParameterizedType);
302             ParameterizedType pRange = (ParameterizedType) range;
303             assertEquals("class com.google.common.collect.Range", pRange.getRawType().toString());
304
305             args = pRange.getActualTypeArguments();
306             assertEquals(1, args.length);
307         } catch (NoSuchMethodException e) {
308             throw new AssertionError("Method length()/range() does not exists in class " + clazz.getSimpleName());
309         }
310     }
311
312     /**
313      * Asserts that class implements given interface.
314      *
315      * @param clazz
316      *            source to test
317      * @param ifc
318      *            expected interface
319      */
320     static void assertImplementsIfc(final Class<?> clazz, final Class<?> ifc) {
321         Class<?>[] interfaces = clazz.getInterfaces();
322         List<Class<?>> ifcsList = Arrays.asList(interfaces);
323         if (!ifcsList.contains(ifc)) {
324             throw new AssertionError(clazz + " should implement " + ifc);
325         }
326     }
327
328     /**
329      * Test if interface generated from augment extends Augmentation interface
330      * with correct generic type.
331      *
332      * @param clazz
333      *            interface generated from augment
334      * @param genericTypeName
335      *            fully qualified name of expected parameter type
336      */
337     static void testAugmentation(final Class<?> clazz, final String genericTypeName) {
338         assertImplementsParameterizedIfc(clazz, AUGMENTATION, genericTypeName);
339     }
340
341     /**
342      * Asserts that class implements interface with given name and generic type
343      * parameter.
344      *
345      * @param clazz
346      *            class to test
347      * @param ifcName
348      *            name of interface
349      * @param genericTypeName
350      *            name of generic type
351      */
352     static void assertImplementsParameterizedIfc(final Class<?> clazz, final String ifcName, final String genericTypeName) {
353         ParameterizedType ifcType = null;
354         for (java.lang.reflect.Type ifc : clazz.getGenericInterfaces()) {
355             if (ifc instanceof ParameterizedType) {
356                 ParameterizedType pt = (ParameterizedType) ifc;
357                 if (ifcName.equals(pt.getRawType().toString())) {
358                     ifcType = pt;
359                 }
360             }
361         }
362         assertNotNull(ifcType);
363
364         java.lang.reflect.Type[] typeArguments = ifcType.getActualTypeArguments();
365         assertEquals(1, typeArguments.length);
366         assertEquals("interface " + genericTypeName, typeArguments[0].toString());
367     }
368
369     /**
370      * Test if source code is compilable.
371      *
372      * @param sourcesOutputDir
373      *            directory containing source files
374      * @param compiledOutputDir
375      *            compiler output directory
376      */
377     static void testCompilation(final File sourcesOutputDir, final File compiledOutputDir) {
378         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
379         StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
380         List<File> filesList = getJavaFiles(sourcesOutputDir);
381         Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
382         Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
383         boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
384         assertTrue("Compilation failed", compiled);
385     }
386
387     /**
388      * Asserts that directory contains exactly given count of files.
389      *
390      * @param dir
391      *            directory to test
392      * @param count
393      *            expected count of files in directory
394      */
395     static void assertFilesCount(final File dir, final int count) {
396         File[] dirContent = dir.listFiles();
397         if (dirContent == null) {
398             throw new AssertionError("File " + dir + " doesn't exists or it's not a directory");
399         } else {
400             assertEquals("Unexpected count of generated files", count, dirContent.length);
401         }
402     }
403
404     /**
405      * Search recursively given directory for *.java files.
406      *
407      * @param directory
408      *            directory to search
409      * @return List of java files found
410      */
411     private static List<File> getJavaFiles(final File directory) {
412         List<File> result = new ArrayList<>();
413         File[] filesToRead = directory.listFiles();
414         if (filesToRead != null) {
415             for (File file : filesToRead) {
416                 if (file.isDirectory()) {
417                     result.addAll(getJavaFiles(file));
418                 } else {
419                     String absPath = file.getAbsolutePath();
420                     if (absPath.endsWith(".java")) {
421                         result.add(file);
422                     }
423                 }
424             }
425         }
426         return result;
427     }
428
429     static List<File> getSourceFiles(final String path) throws Exception {
430         final URI resPath = BaseCompilationTest.class.getResource(path).toURI();
431         final File sourcesDir = new File(resPath);
432         if (sourcesDir.exists()) {
433             final List<File> sourceFiles = new ArrayList<>();
434             final File[] fileArray = sourcesDir.listFiles();
435             if (fileArray == null) {
436                 throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
437             }
438             sourceFiles.addAll(Arrays.asList(fileArray));
439             return sourceFiles;
440         } else {
441             throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
442         }
443     }
444
445     static void deleteTestDir(final File file) {
446         if (file.isDirectory()) {
447             File[] filesToDelete = file.listFiles();
448             if (filesToDelete != null) {
449                 for (File f : filesToDelete) {
450                     deleteTestDir(f);
451                 }
452             }
453         }
454         if (!file.delete()) {
455             throw new RuntimeException("Failed to clean up after test");
456         }
457     }
458
459 }