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