org.evosuite.coverage.dataflow.DefUseFitnessCalculator Maven / Gradle / Ivy
The newest version!
/**
* 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.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.evosuite.Properties;
import org.evosuite.Properties.Criterion;
import org.evosuite.ga.Chromosome;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.TestFitnessFunction;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.execution.ExecutionTrace;
import org.evosuite.utils.ArrayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* This class is like a library containing all methods needed to calculate a
* DefUseCoverage-Fitness
*
* @author Andre Mis
*/
public class DefUseFitnessCalculator {
/** Constant alternativeTime=0l
*/
public static long alternativeTime = 0l;
private final static boolean DEBUG = Properties.DEFUSE_DEBUG_MODE;
private static Logger logger = LoggerFactory.getLogger(DefUseFitnessCalculator.class);
private final DefUseCoverageTestFitness goal;
private final TestChromosome individual;
private final ExecutionResult result;
private final Definition goalDefinition;
private final Use goalUse;
private final TestFitnessFunction goalDefinitionFitness;
private final TestFitnessFunction goalUseFitness;
// private final String goalVariable;
private final String defVariable;
private final String useVariable;
/**
*
* Constructor for DefUseFitnessCalculator.
*
*
* @param goal
* a
* {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness}
* object.
* @param individual
* a {@link org.evosuite.testcase.TestChromosome} object.
* @param result
* a {@link org.evosuite.testcase.execution.ExecutionResult} object.
*/
public DefUseFitnessCalculator(DefUseCoverageTestFitness goal,
TestChromosome individual, ExecutionResult result) {
this.goal = goal;
this.individual = individual;
this.result = result;
this.goalDefinition = goal.getGoalDefinition();
this.goalUse = goal.getGoalUse();
this.goalDefinitionFitness = goal.getGoalDefinitionFitness();
this.goalUseFitness = goal.getGoalUseFitness();
// this.goalVariable = goalUse.getVariableName();
if (goalDefinition == null)
this.defVariable = goalUse.getVariableName();
else
this.defVariable = goalDefinition.getVariableName();
this.useVariable = goalUse.getVariableName();
}
// main Definition-Use fitness calculation methods
/**
* Calculates the DefinitionUseCoverage fitness for the given DUPair on the
* given ExecutionResult
*
* The fitness is calculated as follows:
*
* If the goalDefinition is not passed in the result at all: This method
* returns 1 + normalize(goalDefinitionFitness) where goalDefinition equals
* the BranchCoverageTestFitness for the Branch that the CFGVertex of this
* goals definition is control dependent on (goalDefinitionBranch)
*
* If the goalDefinition is passed, but the goalUse is not passed at all:
* This method returns the normalized BranchCoverageTestFitness for the
* Branch that the CFGVertex of this goals Use is control dependent on
* (goalUseBranch)
*
* If both the goalDefinition and the goalUse were passed at least once in
* the given result: 1. If and only if at any goalUsePosition the active
* definition was the goalDefinition the Definition-Use-Pair of this goal is
* covered and the method returns 0
*
* Otherwise this method returns the minimum of the following: 1. For all
* goalUsePositions if there was an overwriting definition, the normalized
* sum over all such overwriting definitions of the normalized
* BranchCoverageTestFitness for not taking the branch with the overwriting
* definition look at calculateAltenativeFitness()
*
* For all goalDefPositions the normalized BranchCoverageTestFitness for the
* goalUseBranch in the ExecutionTrace where every trace information is
* filtered out except the information traced between the occurrence of the
* goalDefinitionPosition and the next overwritingDefinitionPosition look at
* calculateUseFitnessForDefinitionPosition()
*
* If this goals definition is not a static variable the trace information
* of all constructed objects of the CUT are handled separately and the
* minimum over all individually calculated fitness is returned
*
* @return a double.
*/
public double calculateDUFitness() {
// if (!goalVariable.equals("targetField"))
// return 0.0;
// at first handle special cases where definition is assumed to be
// covered if use is covered:
if (isSpecialDefinition(goalDefinition))
return calculateUseFitnessForCompleteTrace();
// Case 1.
// now check if goalDefinition was passed at all before considering
// individual objects
double defFitness = calculateDefFitnessForCompleteTrace();
if (defFitness != 0)
return 1 + defFitness;
// Case 2.
// if the use was not passed at all just calculate the fitness
// over all objects without any filtering
/* FIXXME: This doesn't seem to make much sense
if (!hasEntriesForId(result.getTrace().getPassedUses(goalVariable),
goalUse.getUseId()))
return calculateUseFitnessForCompleteTrace();
*/
// Case 3.
// filter the trace for each considerable object that passed both the
// goalDefinition and the goalUse, cut the traces between goalDef
// occurrences and overwritingDef occurrences and calculate useFitness
// and possibly overwriting/alternativeFitness
return calculateFitnessForObjects();
}
public double calculateFitnessForObjects() {
// select considerable objects
Set objects = determineConsiderableObjects(goal, result.getTrace());
// calculate minimal fitness over all objects
double fitness = 1;
for (Integer object : objects) {
logger.debug("current object: " + object);
if (!hasEntriesForId(result.getTrace().getPassedDefinitions(defVariable),
object, goalDefinition.getDefId()))
continue;
double newFitness = calculateFitnessForObject(object);
if (newFitness < fitness)
fitness = newFitness;
if (fitness == 0.0)
return 0.0;
}
return fitness;
}
/**
* Calculates the DefUseCoverage fitness for this DefUsePair considering
* only the objectId'th CUT-Object in the ExecutionResult
*
* Gets called for all CUT-objects in the ExecutionResult whenever the
* goalDefinition and the goalUse were passed at least once on that object.
*/
private double calculateFitnessForObject(Integer objectId) {
// filter out trace information from other objects
ExecutionTrace objectTrace = result.getTrace().getTraceForObject(objectId);
double fitness = 1;
// handle special definition case TODO already handled!?
if (isSpecialDefinition(goalDefinition)) {
double useFitness = callTestFitnessFunctionForTrace(objectTrace,
goalUseFitness);
fitness = normalize(useFitness);
if (ArrayUtil.contains(Properties.CRITERION, Criterion.DEFUSE) && fitness == 0.0)
goal.setCovered(individual, objectTrace, objectId);
return fitness;
}
// check if goalDefinition is active at any goalUsePosition
List usePositions = DefUseExecutionTraceAnalyzer.getUsePositions(goalUse,
objectTrace,
objectId);
List goalDefinitionPositions = DefUseExecutionTraceAnalyzer.getDefinitionPositions(goalDefinition,
objectTrace,
objectId);
if (!defVariable.equals(useVariable)) {
logger.debug("Checking an aliasing case: " + goalDefinition + "\n" + goalUse);
}
for (Integer usePos : usePositions) {
int activeDefId = DefUseExecutionTraceAnalyzer.getActiveDefinitionIdAt(defVariable,
objectTrace,
usePos,
objectId);
logger.debug("Activedef at position " + usePos + " is: "
+ DefUsePool.getDefinitionByDefId(activeDefId));
if (activeDefId == goalDefinition.getDefId()) {
// Case 3.1.
if (ArrayUtil.contains(Properties.CRITERION, Criterion.DEFUSE))
goal.setCovered(individual, objectTrace, objectId); {
if(!defVariable.equals(useVariable)) {
// Check if object is equal
Object definedObject = DefUseExecutionTraceAnalyzer.getActiveObjectAtDefinition(result.getTrace(), defVariable, objectId, usePos);
Object usedObject = DefUseExecutionTraceAnalyzer.getActiveObjectAtUse(result.getTrace(), useVariable, objectId, usePos);
logger.info(definedObject+", "+usedObject);
if(definedObject == usedObject) {
logger.debug("That's the target def we're looking for, and objects are equal!");
return 0.0;
}
else {
logger.debug("That's the target def we're looking for, but objects are not equal!");
continue;
}
}
return 0.0;
}
}
}
// Case 3.2.2
// calculate minimal useFitness over all goalDefPositions
// DONE: this can be optimized! for example if the goalDef is never
// overwritten by another
// definition but is passed a lot this causes major overhead that is
// totally unnecessary
// idea: you only have to do this if the last definition for goalVar was
// not goalDefinitionId
if (!goalUse.isRootBranchDependent())
// if goal use is root branch
// dependent useFitness will
// always be 1.0
for (Integer goalDefinitionPos : goalDefinitionPositions) {
double useFitness;
try {
useFitness = calculateUseFitnessForDefinitionPos(objectTrace,
objectId,
goalDefinitionPos);
} catch (UnexpectedFitnessException e) {
continue;
}
// if(useFitness == 0.0)
// throw new
// IllegalStateException("unexpected: should have been detected earlier");
double newFitness = normalize(useFitness);
if (newFitness < fitness)
fitness = newFitness;
}
return fitness;
}
/**
* Determines the BranchCoverageTestFitness of goalDefinitionBranch
* considering the full ExecutionTrace
*
* Is called on every call to getDistance() if the goalDefinition isn't
* special s. isSpecialGoalDefinition()
*/
private double calculateDefFitnessForCompleteTrace() {
if (isSpecialDefinition(goalDefinition))
return 0.0;
// check ExecutionTrace.passedDefinitions first, because calculating
// BranchTestFitness takes time
if (hasEntriesForId(result.getTrace().getPassedDefinitions(goalDefinition.getVariableName()),
goalDefinition.getDefId()))
return 0.0;
// return calculated fitness
double fitness = goalDefinitionFitness.getFitness(individual, result);
// check for false positive: TODO warn?
// this can happen, when a du is within a catch-block, since we
// currently don't handle these correctly in the CDG department
if (fitness == 0.0)
return 1.0;
return normalize(fitness);
}
/**
* Determines the BranchCoverageTestFitness of goalUseBranch considering the
* full ExecutionTrace
*
* Is called on every call to getDistance() if the goalDefinition isn't
* special s. isSpecialGoalDefinition()
*/
private double calculateUseFitnessForCompleteTrace() {
// check ExecutionTrace.passedUses first, because calculating
// BranchTestFitness takes time
if (hasEntriesForId(result.getTrace().getPassedUses(goalUse.getVariableName()),
goalUse.getUseId()))
return 0.0;
// return calculated fitness
double fitness = goalUseFitness.getFitness(individual, result);
// check for false positive: TODO warn?
// this can happen, when a du is within a catch-block, since we
// currently don't handle these correctly in the CDG department
if (fitness == 0.0)
return 1.0;
return normalize(fitness);
}
/**
* Calculates the goalUseFitness for the given goalDefinitionPos as follows:
*
* For every goalDefinitionPosition in the objectTrace for the given
* objectId this method gets called by getDistance() to determine the
* fitness of the goalUseBranch considering only information traced between
* the goalDefinitionPosition and the occurrence of the next overwriting
* definition
*
* In order to do that the ExecutionTrace is filtered using
* calculateFitnessForDURange()
*
* To avoid making unnecessary calculations only calculate the fitness if
* the definition coming before goalDefinitionPos was not the
* goalDefinition. If it was, 1 is returned.
*
* @throws UnexpectedFitnessException
*
*/
private double calculateUseFitnessForDefinitionPos(ExecutionTrace targetTrace,
Integer objectId, int goalDefinitionPos) throws UnexpectedFitnessException {
int previousDefId = DefUseExecutionTraceAnalyzer.getPreviousDefinitionId(goalDefinition.getVariableName(),
targetTrace,
goalDefinitionPos,
objectId);
if (previousDefId == goalDefinition.getDefId())
return 1.0;
int overwritingDefPos = DefUseExecutionTraceAnalyzer.getNextOverwritingDefinitionPosition(goalDefinition,
targetTrace,
goalDefinitionPos,
objectId);
try {
return calculateFitnessForDURange(targetTrace, objectId, goalUseFitness,
goalUse, true, goalDefinitionPos,
overwritingDefPos, true);
} catch (UnexpectedFitnessException e) {
return 1.0;
}
}
/**
* Used to calculate a BranchCoverageTestFitness considering only trace
* information in a given range of duCounter positions
*
* Filters the ExecutionTrace using
* ExecutionTrace.getTraceInDUCounterRange() to only contain information
* made between duCounterStart and duCounterEnd
*
* Additionally, if wantToCoverTargetDU is set all points in the trace where
* the given targetDUBranch would be passed is filtered out in order to
* prevent miscalculations. Again ExecutionTrace.getTraceInDUCounterRange()
* holds more information
*
*
*
* This method gets called for alternative fitness calculation -
* calculateAlternativeFitness() - and in order to determine the
* goalUseBranch fitness between a goalUsePos and its next overwriting
* definition - calculateUseFitnessForDefinitionPos()
*
* @throws UnexpectedFitnessException
*
*
*/
private double calculateFitnessForDURange(ExecutionTrace targetTrace,
Integer objectId, TestFitnessFunction targetFitness, DefUse targetDU,
boolean wantToCoverTargetDU, int duCounterStart, int duCounterEnd,
boolean expectNotToBeZero) throws UnexpectedFitnessException {
// filter trace
ExecutionTrace cutTrace = targetTrace.getTraceInDUCounterRange(targetDU,
wantToCoverTargetDU,
duCounterStart,
duCounterEnd);
// calculate fitness
double fitness = callTestFitnessFunctionForTrace(cutTrace, targetFitness);
// TODO see comment in calculateDUFitness() Case2.
// // sanity check
// if (fitness == 0.0 && !wantToCoverTargetDU) {
//
// System.out.println(this.goal.toString());
//
// System.out.println(cutTrace.toDefUseTraceInformation());
// DefUseExecutionTraceAnalyzer.printFinishCalls(cutTrace);
//
// System.out.println("duPosStart: " + duCounterStart);
// System.out.println("duPosEnd: " + duCounterEnd);
// // int targetUseBranchBytecode =
// // targetDU.getControlDependentBranch()
// // .getInstruction().getInstructionId();
// // System.out.println("targetDU-branch-bytecode: "
// // + targetUseBranchBytecode);
// throw new IllegalStateException(targetFitness.toString()
// + " cant have fitness 0 in this cut trace: "
// + cutTrace.toDefUseTraceInformation(targetDU
// .getDUVariableName(), objectId));
// }
if (expectNotToBeZero && fitness == 0.0)
throw new UnexpectedFitnessException();
// else
// throw new IllegalStateException(
// "avoiding fitness should not be 0 if instruction was actually passed "
// + targetFitness.toString());
return fitness;
}
// other core methods
/**
* Executes the TestFitnessFunction.getFitness() function on the given
* ExecutionResult but using the given targetTrace
*
* The ExecutionResult is left in it's original state after execution
*/
private double callTestFitnessFunctionForTrace(ExecutionTrace targetTrace,
TestFitnessFunction targetFitness) {
ExecutionTrace originalTrace = result.getTrace();
result.setTrace(targetTrace);
double fitness = targetFitness.getFitness(individual, result);
result.setTrace(originalTrace);
return fitness;
}
/**
* Determines whether the given definition is assumed to always be covered
*
* This is the case for static definitions in and
* Parameter-Definitions
*/
private static boolean isSpecialDefinition(Definition definition) {
if (definition == null
|| (definition.isStaticDefUse() && definition.getMethodName().startsWith(""))) {
if (definition == null)
logger.debug("Assume Parameter-Definition to be covered if the Parameter-Use is covered");
else
logger.debug("Assume definition from to always be covered");
return true;
}
return false;
}
/**
* Determines the object Pool of the given trace for this DefUsePair
*
* If the goalVariable is static all objects are considered otherwise only
* those objects that have passed both the goalUse and the goalDefinition
* are considered
*/
private static Set determineConsiderableObjects(
DefUseCoverageTestFitness goal, ExecutionTrace trace) {
String goalVariable = goal.getGoalVariable();
Definition goalDefinition = goal.getGoalDefinition();
Set objectPool = new HashSet();
if (trace.getPassedUses(goalVariable) == null)
return objectPool;
if (trace.getPassedDefinitions(goalVariable) != null)
objectPool.addAll(trace.getPassedDefinitions(goalVariable).keySet());
if (goalDefinition == null || goalDefinition.isStaticDefUse()) {
// in the static case all objects have to be considered
objectPool.addAll(trace.getPassedUses(goalVariable).keySet());
if (DEBUG)
logger.debug("Static-goalVariable! Using all known Objects");
} else {
// on non-static goalVariables only look at objects that have traces
// of defs and uses for the goalVariable
int oldSize = objectPool.size();
objectPool.retainAll(trace.getPassedUses(goalVariable).keySet());
if (DEBUG) {
logger.debug("NON-Static-goalVariable " + goalVariable);
logger.debug("#unused objects: " + (oldSize - objectPool.size()));
Set discardedObjects = new HashSet();
discardedObjects.addAll(trace.getPassedDefinitions(goalVariable).keySet());
discardedObjects.removeAll(trace.getPassedUses(goalVariable).keySet());
for (Integer id : discardedObjects) {
logger.debug(" discarded object " + id);
}
}
}
if (DEBUG) {
logger.debug("#considered objects: " + objectPool.size());
for (Integer id : objectPool) {
logger.debug(" object " + id);
}
}
return objectPool;
}
// auxiliary methods
/**
*
* normalize
*
*
* @param value
* a double.
* @return a double.
*/
public static double normalize(double value) {
// TODO just copied this from FitnessFunction because it was not visible
// from here
return value / (1.0 + value);
}
/**
*
* hasEntryLowerThan
*
*
* @param list
* a {@link java.util.List} object.
* @param border
* a {@link java.lang.Integer} object.
* @return a boolean.
*/
public static boolean hasEntryLowerThan(List list, Integer border) {
for (Integer pos : list)
if (pos < border)
return true;
return false;
}
/**
*
* hasEntryInBetween
*
*
* @param list
* a {@link java.util.List} object.
* @param start
* a {@link java.lang.Integer} object.
* @param end
* a {@link java.lang.Integer} object.
* @return a boolean.
*/
public static boolean hasEntryInBetween(List list, Integer start, Integer end) {
for (Integer pos : list)
if (start < pos && pos < end)
return true;
return false;
}
/**
*
* getMaxEntryLowerThan
*
*
* @param list
* a {@link java.util.List} object.
* @param border
* a {@link java.lang.Integer} object.
* @return a {@link java.lang.Integer} object.
*/
public static Integer getMaxEntryLowerThan(List list, Integer border) {
int lastPos = -1;
for (Integer defPos : list)
if (defPos < border && defPos > lastPos)
lastPos = defPos;
return lastPos;
}
/**
*
* hasEntriesForId
*
*
* @param objectDUMap
* a {@link java.util.Map} object.
* @param targetId
* a int.
* @return a boolean.
*/
public static boolean hasEntriesForId(
Map> objectDUMap, int targetId) {
if (objectDUMap == null)
return false;
for (Integer objectId : objectDUMap.keySet())
if (hasEntriesForId(objectDUMap, objectId, targetId))
return true;
return false;
}
/**
*
* hasEntriesForId
*
*
* @param objectDUMap
* a {@link java.util.Map} object.
* @param objectId
* a {@link java.lang.Integer} object.
* @param targetId
* a int.
* @return a boolean.
*/
public static boolean hasEntriesForId(
Map> objectDUMap, Integer objectId,
int targetId) {
if (objectDUMap == null)
return false;
if (objectDUMap.get(objectId) == null)
return false;
for (Integer defId : objectDUMap.get(objectId).values())
if (defId.intValue() == targetId)
return true;
return false;
}
/**
* Only a sanity check function for testing purposes
*
* @param goal
* a
* {@link org.evosuite.coverage.dataflow.DefUseCoverageTestFitness}
* object.
* @param individual
* a {@link org.evosuite.ga.Chromosome} object.
* @param trace
* a {@link org.evosuite.testcase.execution.ExecutionTrace} object.
* @return a boolean.
*/
public static boolean traceCoversGoal(DefUseCoverageTestFitness goal,
Chromosome individual, ExecutionTrace trace) {
String goalVariable = goal.getGoalVariable();
Use goalUse = goal.getGoalUse();
Definition goalDefinition = goal.getGoalDefinition();
if (trace.getPassedUses(goalVariable) == null)
return false;
Set objectPool = determineConsiderableObjects(goal, trace);
for (Integer objectID : objectPool) {
List usePositions = DefUseExecutionTraceAnalyzer.getUsePositions(goalUse,
trace,
objectID);
// use not reached
if (usePositions.size() == 0)
continue;
// if (goalUse.isParameterUse())
// return true;
if (isSpecialDefinition(goalDefinition))
return true;
for (Integer usePos : usePositions) {
if (DefUseExecutionTraceAnalyzer.getActiveDefinitionIdAt(goalVariable,
trace, usePos,
objectID) == goalDefinition.getDefId())
return true;
}
}
return false;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy