/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.runtime; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.evosuite.annotations.EvoSuiteTest; import org.junit.Test; import org.evosuite.runtime.instrumentation.EvoClassLoader; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Special JUnit Runner needed for the test cases generated by EvoSuite * * @author arcuri * */ public class EvoRunner extends BlockJUnit4ClassRunner { /* * We need this class due to some weird behavior of JVM */ private static final Logger logger = LoggerFactory.getLogger(EvoRunner.class); /** * Dirty hack, to use with care. * In some very special cases, we want to skip agent instrumentation. * Still, we would need to use a classloader that will do such instrumentation. * This is for example done in -measureCoverage, as we need a more details instrumentation, * and, at the same time, we want to avoid a double instrumentation from agent */ public static boolean useAgent = true; /** * Another dirty hack, to use with care. This is to make useSeparateClassLoader * work together with -measureCoverage */ public static boolean useClassLoader = true; public EvoRunner(Class<?> klass) throws InitializationError { /* * extremely important that getClass is called _BEFORE_ super is executed. * The constructor of BlockJUnit4ClassRunner does reflection on klass, eg * to check that it has only one constructor. * For some arcane reasons, such reflection code ends up in native JVM code * that "might" start the loading of some classes whose type is used for * variables and casting inside the methods of "klass", * although the code of those methods is _NOT_ executed (note: not * talking of static initializers here). */ super(getClass(klass)); } private static Class<?> getClass(Class<?> klass) throws InitializationError{ EvoRunnerParameters ep = klass.getAnnotation(EvoRunnerParameters.class); if(ep == null){ throw new IllegalStateException("EvoSuite test class "+klass.getName()+ " is not annotated with "+EvoRunnerParameters.class.getName()); } RuntimeSettings.resetStaticState = ep.resetStaticState(); RuntimeSettings.mockJVMNonDeterminism = ep.mockJVMNonDeterminism(); RuntimeSettings.mockGUI = ep.mockGUI(); RuntimeSettings.useVFS = ep.useVFS(); RuntimeSettings.useVNET = ep.useVNET(); RuntimeSettings.useSeparateClassLoader = ep.separateClassLoader(); RuntimeSettings.useJEE = ep.useJEE(); if(RuntimeSettings.useSeparateClassLoader && useClassLoader) { return getFromEvoSuiteClassloader(klass); } if(useAgent) { org.evosuite.runtime.agent.InstrumentingAgent.initialize(); } org.evosuite.runtime.agent.InstrumentingAgent.activate(); try { /* * be sure that reflection on "klass" is executed here when * the agent is active */ klass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { //shouldn't really happen logger.error("Failed to initialize test class "+klass.getName()); } org.evosuite.runtime.agent.InstrumentingAgent.deactivate(); return klass; } private static Class<?> getFromEvoSuiteClassloader(Class<?> clazz) throws InitializationError { try { /* * properties like REPLACE_CALLS will be set directly in the JUnit files */ // LoggingUtils.loadLogbackForEvoSuite(); /* * This approach does throw away all the possible instrumentation done on the input clazz, * eg code coverage of Emma, Cobertura, Javalanche, etc. * Furthermore, if the classloader used to load EvoRunner is not the same as CUT, * then loading CUTs will fail (this does happen in "mvn test") */ EvoClassLoader classLoader = new EvoClassLoader(); classLoader.skipInstrumentation(clazz.getName()); Thread.currentThread().setContextClassLoader(classLoader); return Class.forName(clazz.getName(), true, classLoader); } catch (ClassNotFoundException e) { throw new InitializationError(e); } } /** * Returns the methods that run tests. Default implementation returns all * methods annotated with {@code @Test} on this class and superclasses that * are not overridden. */ @Override protected List<FrameworkMethod> computeTestMethods() { Set<FrameworkMethod> testMethods = new HashSet<FrameworkMethod>(); testMethods.addAll(getTestClass().getAnnotatedMethods(EvoSuiteTest.class)); testMethods.addAll(getTestClass().getAnnotatedMethods(Test.class)); return new ArrayList<FrameworkMethod>(testMethods); } /** * Adds to {@code errors} for each method annotated with {@code @Test}that * is not a public, void instance method with no arguments. */ @Override protected void validateTestMethods(List<Throwable> errors) { Set<FrameworkMethod> testMethods = new HashSet<FrameworkMethod>(); testMethods.addAll(getTestClass().getAnnotatedMethods(EvoSuiteTest.class)); testMethods.addAll(getTestClass().getAnnotatedMethods(Test.class)); for (FrameworkMethod eachTestMethod : testMethods) { eachTestMethod.validatePublicVoidNoArg(false, errors); } } }