org.evosuite.coverage.dataflow.DefUseCoverageFactory Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2018 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 .
*/
package org.evosuite.coverage.dataflow;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.evosuite.Properties;
import org.evosuite.TestGenerationContext;
import org.evosuite.coverage.dataflow.DefUseCoverageTestFitness.DefUsePairType;
import org.evosuite.coverage.dataflow.analysis.AllUsesAnalysis;
import org.evosuite.graphs.GraphPool;
import org.evosuite.graphs.ccfg.ClassControlFlowGraph;
import org.evosuite.graphs.cfg.BytecodeInstruction;
import org.evosuite.rmi.ClientServices;
import org.evosuite.statistics.RuntimeVariable;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testsuite.AbstractFitnessFactory;
import org.evosuite.utils.LoggingUtils;
import org.evosuite.utils.JdkPureMethodsList;
import org.objectweb.asm.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* DefUseCoverageFactory class.
*
*
* @author Andre Mis
*/
public class DefUseCoverageFactory extends
AbstractFitnessFactory {
private static final Logger logger = LoggerFactory.getLogger(DefUseCoverageFactory.class);
// TestSuiteMinimizer seems to call getCoverageGoals() a second time
// and since analysis takes a little ...
private static boolean called = false;
private static List duGoals; // TODO: What's the difference to goals?
private static List goals;
// map of all NON-parameter-goals
private static Map> goalMap = new HashMap>();
private static Map goalCounts = new HashMap();
/**
*
* getDUGoals
*
*
* @return a {@link java.util.List} object.
*/
public static List getDUGoals() {
if (!called)
computeGoals();
return duGoals;
}
/*
* (non-Javadoc)
*
* @see
* org.evosuite.coverage.TestFitnessFactory#getCoverageGoals()
*/
/** {@inheritDoc} */
@Override
public List getCoverageGoals() {
if (!called)
computeGoals();
return goals;
}
/**
* Determines all goals that need to get covered in order to fulfill
* DefUseCoverage
*
* Those are the following: - for each parameterUse this method creates a
* goal trying to cover i - for each duPair with a definition clear path
* inside the methods of the CUT a goal is created - for each definition in
* the CUT with a clear path to an exit of its method and each use with a
* clear path from its methods entry a goal is created
*/
public static void computeGoals() {
categorizeFieldMethodCalls();
// XXX testing purposes
/*for(String methodInCCFG : GraphPool.getInstance(TestGenerationContext.getClassLoader()).getRawCFGs(Properties.TARGET_CLASS).keySet()) {
if(GraphPool.getInstance(TestGenerationContext.getClassLoader()).getCCFG(Properties.TARGET_CLASS).isPure(methodInCCFG))
LoggingUtils.getEvoLogger().debug("PURE method:\t"+methodInCCFG);
else
LoggingUtils.getEvoLogger().debug("IMPURE method:\t"+methodInCCFG);
} */
long start = System.currentTimeMillis();
LoggingUtils.getEvoLogger().info("starting DefUse-Coverage goal generation");
duGoals = new ArrayList();
if(!GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).canMakeCCFGForClass(Properties.TARGET_CLASS)) {
goals = new ArrayList();
logger.info("Have no CFGs, is this an interface?");
return;
}
LoggingUtils.getEvoLogger().info("* Creating DefUse-Pairs from CCFG...");
duGoals.addAll(getCCFGPairs());
LoggingUtils.getEvoLogger().info(" ..created " + getIntraMethodGoalsCount()
+ " intra-method-, "
+ getInterMethodGoalsCount()
+ " inter-method- and "
+ getIntraClassGoalsCount()
+ " intra-class-pairs");
LoggingUtils.getEvoLogger().info(" "+duGoals.toString());
LoggingUtils.getEvoLogger().info("* Creating parameter goals...");
duGoals.addAll(getParameterGoals());
LoggingUtils.getEvoLogger().info(" created " + getParamGoalsCount()
+ " parameter goals");
called = true;
goals = new ArrayList();
goals.addAll(duGoals);
long end = System.currentTimeMillis();
goalComputationTime = end - start;
LoggingUtils.getEvoLogger().info("* Goal computation took: "
+ goalComputationTime + "ms");
ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.IntraMethodPairs,
getIntraMethodGoalsCount());
ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.InterMethodPairs,
getInterMethodGoalsCount());
ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.ParameterPairs,
getParamGoalsCount());
ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.IntraClassPairs,
getIntraClassGoalsCount());
ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.DefUsePairs,
goals.size());
}
/**
* Determines for all method calls on fields of the CUT whether the call is
* to a pure or impure method. For these calls Uses and Definitions are
* created respectively.
*
* Since purity analysis is used here and requires all classes along the
* call tree to be completely analyzed this part of the CUT analysis can not
* be done in the CFGMethodAdapter like the rest of it.
*
*/
private static void categorizeFieldMethodCalls() {
Set fieldMethodCalls = DefUsePool.retrieveFieldMethodCalls();
LoggingUtils.getEvoLogger().info("Categorizing field method calls: "
+ fieldMethodCalls.size());
for (BytecodeInstruction fieldMethodCall : fieldMethodCalls) {
if (GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).canMakeCCFGForClass(fieldMethodCall.getCalledMethodsClass())) {
ClassControlFlowGraph ccfg = GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).getCCFG(fieldMethodCall.getCalledMethodsClass());
if (ccfg.isPure(fieldMethodCall.getCalledMethod())) {
if (!DefUsePool.addAsUse(fieldMethodCall))
throw new IllegalStateException(
"unable to register field method call as a use "
+ fieldMethodCall.toString());
} else {
if (!DefUsePool.addAsDefinition(fieldMethodCall))
throw new IllegalStateException(
"unable to register field method call as a definition "
+ fieldMethodCall.toString());
}
} else {
String toAnalyze = fieldMethodCall.getCalledMethodsClass() + "."
+ fieldMethodCall.getCalledMethodName();
if (toAnalyze != null && toAnalyze.startsWith("java.")) {
Type[] parameters = org.objectweb.asm.Type.getArgumentTypes(fieldMethodCall.getMethodCallDescriptor());
String newParams = "";
if (parameters.length != 0) {
for (Type i : parameters) {
newParams = newParams + "," + i.getClassName();
}
newParams = newParams.substring(1, newParams.length());
}
toAnalyze = fieldMethodCall.getCalledMethodsClass() + "."
+ fieldMethodCall.getCalledMethodName() + "(" + newParams
+ ")";
//System.out.println(toAnalyze);
if (JdkPureMethodsList.instance.checkPurity(toAnalyze)) {
if (!DefUsePool.addAsUse(fieldMethodCall))
throw new IllegalStateException(
"unable to register field method call as a use "
+ fieldMethodCall.toString());
} else {
if (!DefUsePool.addAsDefinition(fieldMethodCall))
throw new IllegalStateException(
"unable to register field method call as a definition "
+ fieldMethodCall.toString());
}
} else {
if (!DefUsePool.addAsUse(fieldMethodCall))
throw new IllegalStateException(
"unable to register field method call as a use "
+ fieldMethodCall.toString());
}
}
}
}
private static Set getCCFGPairs() {
ClassControlFlowGraph ccfg = GraphPool.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).getCCFG(Properties.TARGET_CLASS);
AllUsesAnalysis aua = new AllUsesAnalysis(ccfg);
Set r = aua.determineDefUsePairs();
return r;
}
/**
* Given a definition and a use, this method creates a DefUseCoverageGoal
* for this DefUsePair.
*
* @param def
* The definition of the goal
* @param use
* The use of the goal
* @return The created DefUseCoverageGoal
* @param type
* a
* {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness.DefUsePairType}
* object.
*/
public static DefUseCoverageTestFitness createGoal(Definition def, Use use,
DefUseCoverageTestFitness.DefUsePairType type) {
DefUseCoverageTestFitness goal = new DefUseCoverageTestFitness(def, use, type);
if (registerGoal(goal))
return goal;
else {
// System.out.println("Discarding goal: "+goal.toString());
return null;
}
}
/**
* Convenience method that retrieves the Definition and Use object for the
* given BytecodeInstructions from the DefUsePool and calls
* createGoal(Definition,Use)
*
* @param def
* a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object.
* @param use
* a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object.
* @param type
* a
* {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness.DefUsePairType}
* object.
* @return a
* {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness}
* object.
*/
public static DefUseCoverageTestFitness createGoal(BytecodeInstruction def,
BytecodeInstruction use, DefUseCoverageTestFitness.DefUsePairType type) {
if (def == null)
throw new IllegalArgumentException("null given as def");
if (use == null)
throw new IllegalArgumentException("null given as use");
Definition definition = DefUsePool.getDefinitionByInstruction(def);
Use usee = DefUsePool.getUseByInstruction(use);
if (definition == null || usee == null) // can happen in (very, very)
// weird cases, ignoring that
// for now
return null;
return createGoal(definition, usee, type);
}
private static boolean registerGoal(DefUseCoverageTestFitness goal) {
if (!goalMap.containsKey(goal.getGoalDefinition()))
goalMap.put(goal.getGoalDefinition(),
new HashMap