/** * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) * and/or other contributors as indicated by the @authors tag. See the * copyright.txt file in the distribution for a full listing of all * contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mapstruct.ap.testutil.runner; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; /** * Internal test runner that runs the tests of one class for one specific compiler implementation. * * @author Andreas Gudian */ class InnerAnnotationProcessorRunner extends BlockJUnit4ClassRunner { static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader(); private final Class<?> klass; private final Compiler compiler; private final CompilationCache compilationCache; private Class<?> klassToUse; private ReplacableTestClass replacableTestClass; /** * @param klass the test class * * @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)} */ InnerAnnotationProcessorRunner(Class<?> klass, Compiler compiler) throws Exception { super( klass ); this.klass = klass; this.compiler = compiler; this.compilationCache = new CompilationCache(); } /** * newly loads the class with the test class loader and sets that loader as context class loader of the thread * * @param klass the class to replace * * @return the class loaded with the test class loader */ private static Class<?> replaceClassLoaderAndClass(Class<?> klass) { replaceContextClassLoader( klass ); try { return Thread.currentThread().getContextClassLoader().loadClass( klass.getName() ); } catch ( ClassNotFoundException e ) { throw new RuntimeException( e ); } } private static void replaceContextClassLoader(Class<?> klass) { ModifiableURLClassLoader testClassLoader = new ModifiableURLClassLoader().withOriginOf( klass ); Thread.currentThread().setContextClassLoader( testClassLoader ); } @Override protected TestClass createTestClass(final Class<?> testClass) { replacableTestClass = new ReplacableTestClass( testClass ); return replacableTestClass; } private FrameworkMethod replaceFrameworkMethod(FrameworkMethod m) { try { return new FrameworkMethod( klassToUse.getDeclaredMethod( m.getName(), m.getMethod().getParameterTypes() ) ); } catch ( NoSuchMethodException e ) { throw new RuntimeException( e ); } } @Override protected Statement methodBlock(FrameworkMethod method) { CompilingStatement statement = createCompilingStatement( method ); if ( statement.needsRecompilation() ) { klassToUse = replaceClassLoaderAndClass( klass ); replacableTestClass.replaceClass( klassToUse ); } method = replaceFrameworkMethod( method ); Statement next = super.methodBlock( method ); statement.setNextStatement( next ); return statement; } private CompilingStatement createCompilingStatement(FrameworkMethod method) { if ( compiler == Compiler.JDK ) { return new JdkCompilingStatement( method, compilationCache ); } else { return new EclipseCompilingStatement( method, compilationCache ); } } @Override protected String getName() { return "[" + compiler.name().toLowerCase() + "]"; } @Override protected String testName(FrameworkMethod method) { return method.getName() + getName(); } }