2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.java.api.generator;
10 import static com.google.common.base.Preconditions.checkState;
11 import static org.hamcrest.CoreMatchers.instanceOf;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertThrows;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
20 import java.io.FileNotFoundException;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.Modifier;
26 import java.lang.reflect.ParameterizedType;
27 import java.lang.reflect.Type;
29 import java.net.URISyntaxException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import javax.tools.Diagnostic;
34 import javax.tools.JavaCompiler;
35 import javax.tools.JavaFileObject;
36 import javax.tools.StandardJavaFileManager;
37 import javax.tools.ToolProvider;
39 public final class CompilationTestUtils {
40 public static final String FS = File.separator;
41 static final String BASE_PKG = "org.opendaylight.yang.gen.v1";
43 static final String TEST_PATH = "target" + FS + "test";
44 static final File TEST_DIR = new File(TEST_PATH);
46 static final String GENERATOR_OUTPUT_PATH = TEST_PATH + FS + "src";
47 static final File GENERATOR_OUTPUT_DIR = new File(GENERATOR_OUTPUT_PATH);
48 private static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
49 static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
51 static final String AUGMENTATION = "interface org.opendaylight.yangtools.yang.binding.Augmentation";
52 static final String BASE_PATH = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1";
53 static final String BASE_SVC_PATH = "org" + FS + "opendaylight" + FS + "yang" + FS + "svc" + FS + "v1";
54 static final String NS_TEST = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
55 static final String NS_SVC_TEST = BASE_SVC_PATH + FS + "urn" + FS + "opendaylight" + FS + "test" + FS + "rev131008";
56 static final String NS_FOO = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "foo" + FS + "rev131008";
57 static final String NS_SVC_FOO = BASE_SVC_PATH + FS + "urn" + FS + "opendaylight" + FS + "foo" + FS + "rev131008";
58 static final String NS_BAR = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "bar" + FS + "rev131008";
59 static final String NS_SVC_BAR = BASE_SVC_PATH + FS + "urn" + FS + "opendaylight" + FS + "bar" + FS + "rev131008";
60 static final String NS_BAZ = BASE_PATH + FS + "urn" + FS + "opendaylight" + FS + "baz" + FS + "rev131008";
61 static final String NS_SVC_BAZ = BASE_SVC_PATH + FS + "urn" + FS + "opendaylight" + FS + "baz" + FS + "rev131008";
62 static final String NS_BUG5882 = BASE_PATH + FS + "urn" + FS + "yang" + FS + "foo" + FS + "rev160102";
64 private CompilationTestUtils() {
68 static File compilerOutput(final String name) {
69 return createDirectory(CompilationTestUtils.COMPILER_OUTPUT_PATH + CompilationTestUtils.FS + name);
72 static File generatorOutput(final String name) {
73 return createDirectory(CompilationTestUtils.GENERATOR_OUTPUT_PATH + CompilationTestUtils.FS + name);
76 private static File createDirectory(final String path) {
77 final File ret = new File(path);
78 checkState(ret.mkdir(), "Failed to create test directory %s", path);
83 * Method to clean resources. It is manually called at the end of each test instead of marking it with @After
84 * annotation to prevent removing generated code if test fails.
86 static void cleanUp(final File... resourceDirs) {
87 for (File resourceDir : resourceDirs) {
88 if (resourceDir.exists()) {
89 deleteTestDir(resourceDir);
95 * Asserts that class contains field with given name and type.
97 * @param clazz class to test
98 * @param name field name
99 * @param type field type
100 * @return field with given name if present in class
102 static Field assertContainsField(final Class<?> clazz, final String name, final Class<?> type) {
104 Field field = clazz.getDeclaredField(name);
105 assertEquals(type, field.getType());
107 } catch (NoSuchFieldException e) {
108 throw new AssertionError("Field " + name + " does not exist in class " + clazz.getSimpleName(), e);
113 * Asserts that class contains field with given name and value. Method tries to create new instance of class
114 * and get value of field. If class constructor contains any arguments, class is instantiated with null values.
116 * @param clazz class to test
117 * @param name name of field
118 * @param returnType return type of field
119 * @param expectedValue expected value of field
120 * @param constructorArgs constructor arguments of class to test
122 static void assertContainsFieldWithValue(final Class<?> clazz, final String name, final Class<?> returnType,
123 final Object expectedValue, final Class<?>... constructorArgs) {
124 Object[] initargs = null;
125 if (constructorArgs != null && constructorArgs.length > 0) {
126 initargs = new Object[constructorArgs.length];
127 for (int i = 0; i < constructorArgs.length; i++) {
131 assertContainsFieldWithValue(clazz, name, returnType, expectedValue, constructorArgs, initargs);
135 * Asserts that class contains field with given name, return type and value.
137 * @param clazz class to test
138 * @param name name of field
139 * @param returnType return type of field
140 * @param expectedValue expected value of field
141 * @param constructorArgs array of constructor arguments classes
142 * @param initargs array of constructor values
144 static void assertContainsFieldWithValue(final Class<?> clazz, final String name, final Class<?> returnType,
145 final Object expectedValue, final Class<?>[] constructorArgs, final Object... initargs) {
146 Field field = assertContainsField(clazz, name, returnType);
147 field.setAccessible(true);
150 if ((field.getModifiers() & Modifier.STATIC) == 0) {
152 Constructor<?> cls = clazz.getDeclaredConstructor(constructorArgs);
153 obj = cls.newInstance(initargs);
154 } catch (ReflectiveOperationException e) {
155 throw new AssertionError("Failed to instantiate object for " + clazz, e);
162 assertEquals(expectedValue, field.get(obj));
163 } catch (IllegalArgumentException | IllegalAccessException e) {
164 throw new AssertionError("Failed to get field " + name + " of class " + clazz, e);
169 * Asserts that class contains constructor with parameter types.
171 * @param clazz class to test
172 * @param args array of argument classes
174 static Constructor<?> assertContainsConstructor(final Class<?> clazz, final Class<?>... args) {
176 return clazz.getDeclaredConstructor(args);
177 } catch (NoSuchMethodException e) {
178 throw new AssertionError("Constructor with args " + Arrays.toString(args) + " does not exists in class "
179 + clazz.getSimpleName(), e);
184 * Asserts that class contains method with given name, return type and parameter types.
186 * @param clazz class to test
187 * @param returnType method return type
188 * @param name method name
189 * @param args array of parameter type classes
190 * @return method with given name, return type and parameter types
192 static Method assertContainsMethod(final Class<?> clazz, final Class<?> returnType, final String name,
193 final Class<?>... args) {
195 Method method = clazz.getDeclaredMethod(name, args);
196 assertEquals(returnType, method.getReturnType());
198 } catch (NoSuchMethodException e) {
199 throw new AssertionError("Method " + name + " with args " + Arrays.toString(args)
200 + " does not exists in class " + clazz.getSimpleName(), e);
205 * Asserts that class contains method with given name and return type.
207 * @param clazz class to test
208 * @param returnTypeStr name of method return type
209 * @param name method name
210 * @param loader current class loader
212 static void assertContainsMethod(final Class<?> clazz, final String returnTypeStr, final String name,
213 final ClassLoader loader) {
216 returnType = Class.forName(returnTypeStr, true, loader);
217 Method method = clazz.getMethod(name);
218 assertEquals(returnType, method.getReturnType());
219 } catch (ClassNotFoundException e) {
220 throw new AssertionError("Return type of method '" + name + "' not found", e);
221 } catch (NoSuchMethodException e) {
222 throw new AssertionError("Method " + name + " does not exists in class " + clazz.getSimpleName(), e);
227 * Asserts that class contains hashCode, equals and toString methods.
229 * @param clazz class to test
231 static void assertContainsDefaultMethods(final Class<?> clazz) {
232 assertContainsMethod(clazz, Integer.TYPE, "hashCode");
233 assertContainsMethod(clazz, Boolean.TYPE, "equals", Object.class);
234 assertContainsMethod(clazz, String.class, "toString");
238 * Asserts that constructor contains check for illegal argument.
240 * @param constructor constructor to invoke
241 * @param errorMsg expected error message
242 * @param args constructor arguments
244 static void assertContainsRestrictionCheck(final Constructor<?> constructor, final String errorMsg,
245 final Object... args) throws ReflectiveOperationException {
246 final var cause = assertThrows(InvocationTargetException.class, () -> constructor.newInstance(args)).getCause();
247 assertThat(cause, instanceOf(IllegalArgumentException.class));
248 assertEquals(errorMsg, cause.getMessage());
252 * Asserts that method contains check for illegal argument.
254 * @param obj object to test (can be null, if method is static)
255 * @param method method to invoke
256 * @param errorMsg expected error message
257 * @param args constructor arguments
259 static void assertContainsRestrictionCheck(final Object obj, final Method method, final String errorMsg,
260 final Object... args) throws ReflectiveOperationException {
261 final var cause = assertThrows(InvocationTargetException.class, () -> method.invoke(obj, args)).getCause();
262 assertThat(cause, instanceOf(IllegalArgumentException.class));
263 assertEquals(errorMsg, cause.getMessage());
267 * Asserts that class implements given interface.
269 * @param clazz source to test
270 * @param ifc expected interface
272 static void assertImplementsIfc(final Class<?> clazz, final Class<?> ifc) {
273 List<Class<?>> ifcsList = Arrays.asList(clazz.getInterfaces());
274 if (!ifcsList.contains(ifc)) {
275 throw new AssertionError(clazz + " should implement " + ifc);
280 * Test if interface generated from augment extends Augmentation interface with correct generic type.
282 * @param clazz interface generated from augment
283 * @param genericTypeName fully qualified name of expected parameter type
285 static void testAugmentation(final Class<?> clazz, final String genericTypeName) {
286 assertImplementsParameterizedIfc(clazz, AUGMENTATION, genericTypeName);
290 * Asserts that class implements interface with given name and generic type parameter.
292 * @param clazz class to test
293 * @param ifcName name of interface
294 * @param genericTypeName name of generic type
296 static void assertImplementsParameterizedIfc(final Class<?> clazz, final String ifcName,
297 final String genericTypeName) {
298 ParameterizedType ifcType = null;
299 for (Type ifc : clazz.getGenericInterfaces()) {
300 if (ifc instanceof ParameterizedType) {
301 ParameterizedType pt = (ParameterizedType) ifc;
302 if (ifcName.equals(pt.getRawType().toString())) {
307 assertNotNull(ifcType);
309 Type[] typeArg = ifcType.getActualTypeArguments();
310 assertEquals(1, typeArg.length);
311 Type typeArgument = typeArg[0];
312 assertThat(typeArgument, instanceOf(Class.class));
313 Class<?> argClass = (Class<?>) typeArgument;
314 assertEquals(genericTypeName, argClass.getName());
315 assertTrue(argClass.isInterface());
319 * Test if source code is compilable.
321 * @param sourcesOutputDir directory containing source files
322 * @param compiledOutputDir compiler output directory
324 static void testCompilation(final File sourcesOutputDir, final File compiledOutputDir) {
325 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
326 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
327 List<File> filesList = getJavaFiles(sourcesOutputDir);
328 Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
329 Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
331 List<Diagnostic<?>> diags = new ArrayList<>();
332 boolean compiled = compiler.getTask(null, null, diags::add, options, null, compilationUnits).call();
334 fail("Compilation failed with " + diags);
339 * Asserts that directory contains exactly given count of files.
344 * expected count of files in directory
346 static void assertFilesCount(final File dir, final int count) {
347 File[] dirContent = dir.listFiles();
348 if (dirContent == null) {
349 throw new AssertionError("File " + dir + " doesn't exists or it's not a directory");
352 assertEquals("Unexpected count of generated files", count, dirContent.length);
356 * Search recursively given directory for *.java files.
358 * @param directory directory to search
359 * @return List of java files found
361 private static List<File> getJavaFiles(final File directory) {
362 List<File> result = new ArrayList<>();
363 File[] filesToRead = directory.listFiles();
364 if (filesToRead != null) {
365 for (File file : filesToRead) {
366 if (file.isDirectory()) {
367 result.addAll(getJavaFiles(file));
369 String absPath = file.getAbsolutePath();
370 if (absPath.endsWith(".java")) {
379 static List<File> getSourceFiles(final String path) throws FileNotFoundException, URISyntaxException {
380 final URI resPath = BaseCompilationTest.class.getResource(path).toURI();
381 final File sourcesDir = new File(resPath);
382 if (!sourcesDir.exists()) {
383 throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
386 final List<File> sourceFiles = new ArrayList<>();
387 final File[] fileArray = sourcesDir.listFiles();
388 if (fileArray == null) {
389 throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
391 sourceFiles.addAll(Arrays.asList(fileArray));
395 static void deleteTestDir(final File file) {
396 if (file.isDirectory()) {
397 File[] filesToDelete = file.listFiles();
398 if (filesToDelete != null) {
399 for (File f : filesToDelete) {
404 if (!file.delete()) {
405 throw new RuntimeException("Failed to clean up after test");