org.evosuite.coverage.mutation.StrongMutationTestFitness 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.mutation;
import org.evosuite.Properties;
import org.evosuite.assertion.*;
import org.evosuite.coverage.TestCoverageGoal;
import org.evosuite.ga.archive.Archive;
import org.evosuite.ga.stoppingconditions.MaxStatementsStoppingCondition;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.execution.ExecutionTrace;
import org.evosuite.testcase.execution.TestCaseExecutor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
*
* StrongMutationTestFitness class.
*
*
* @author fraser
*/
public class StrongMutationTestFitness extends MutationTestFitness {
private static final long serialVersionUID = -262199037689935052L;
/** Constant observerClasses
*/
protected static Class>[] observerClasses = { PrimitiveTraceEntry.class,
ComparisonTraceEntry.class, InspectorTraceEntry.class,
PrimitiveFieldTraceEntry.class, NullTraceEntry.class, ArrayTraceEntry.class, ArrayLengthTraceEntry.class };
/** Constant observers
*/
protected static AssertionTraceObserver>[] observers = {
new PrimitiveTraceObserver(), new ComparisonTraceObserver(),
new InspectorTraceObserver(), new PrimitiveFieldTraceObserver(),
new NullTraceObserver(), new ArrayTraceObserver(), new ArrayLengthObserver() };
/**
*
* Constructor for StrongMutationTestFitness.
*
*
* @param mutation
* a {@link org.evosuite.coverage.mutation.Mutation} object.
*/
public StrongMutationTestFitness(Mutation mutation) {
super(mutation);
for (AssertionTraceObserver> observer : observers) {
logger.debug("StrongMutation adding observer " + observer);
TestCaseExecutor.getInstance().addObserver(observer);
}
}
/** {@inheritDoc} */
@Override
public ExecutionResult runTest(TestCase test) {
return runTest(test, null);
}
/** {@inheritDoc} */
public static ExecutionResult runTest(TestCase test, Mutation mutant) {
ExecutionResult result = new ExecutionResult(test, mutant);
try {
if (mutant != null)
logger.debug("Executing test for mutant " + mutant.getId() + ": \n"
+ test.toCode());
else
logger.debug("Executing test without mutant");
if (mutant != null)
MutationObserver.activateMutation(mutant);
result = TestCaseExecutor.getInstance().execute(test);
if (mutant != null)
MutationObserver.deactivateMutation(mutant);
int num = test.size();
if (!result.noThrownExceptions()) {
num = result.getFirstPositionOfThrownException();
}
//if (mutant == null)
MaxStatementsStoppingCondition.statementsExecuted(num);
int i = 0;
for (AssertionTraceObserver> observer : observers) {
result.setTrace(observer.getTrace(), observerClasses[i++]);
}
} catch (Exception e) {
throw new Error(e);
}
return result;
}
private MutationExecutionResult getMutationResult(ExecutionResult originalResult,
ExecutionResult mutationResult) {
MutationExecutionResult result = new MutationExecutionResult();
if (TestCoverageGoal.hasTimeout(mutationResult)) {
logger.debug("Found timeout in mutant!");
MutationTimeoutStoppingCondition.timeOut(mutation);
result.setHasTimeout(true);
}
if (mutationResult.noThrownExceptions()) {
result.setHasException(true);
}
int numAssertions = getNumAssertions(originalResult, mutationResult);
result.setNumAssertions(numAssertions);
if (numAssertions == 0) {
double impact = getSumDistance(originalResult.getTrace(),
mutationResult.getTrace());
result.setImpact(impact);
}
return result;
}
private Set getDifference(
Map>> orig,
Map>> mutant) {
Map> handled = new HashMap>();
Set differ = new HashSet();
for (Entry>> entry : orig.entrySet()) {
if (!handled.containsKey(entry.getKey()))
handled.put(entry.getKey(), new HashSet());
for (Entry> method_entry : entry.getValue().entrySet()) {
if (!mutant.containsKey(entry.getKey())) {
// Class was not executed on mutant, so add method
logger.debug("Found class difference: " + entry.getKey());
differ.add(entry.getKey());
} else {
// Class was also executed on mutant
if (!mutant.get(entry.getKey()).containsKey(method_entry.getKey())) {
// Method was not executed on mutant, so add method
logger.debug("Found method difference: " + method_entry.getKey());
differ.add(entry.getKey() + "." + method_entry.getKey());
} else {
// Method was executed on mutant
for (Entry line_entry : method_entry.getValue().entrySet()) {
if (!mutant.get(entry.getKey()).get(method_entry.getKey()).containsKey(line_entry.getKey())) {
// Line was not executed on mutant, so add
logger.debug("Found line difference: "
+ line_entry.getKey() + ": "
+ line_entry.getValue());
differ.add(entry.getKey() + "." + method_entry.getKey()
+ ":" + line_entry.getKey());
} else {
if (!mutant.get(entry.getKey()).get(method_entry.getKey()).get(line_entry.getKey()).equals(line_entry.getValue())) {
// Line coverage differs, so add
differ.add(entry.getKey() + "."
+ method_entry.getKey() + ":"
+ line_entry.getKey());
logger.debug("Found line difference: "
+ line_entry.getKey() + ": "
+ line_entry.getValue());
}
}
}
if (!method_entry.getValue().equals(mutant.get(entry.getKey()).get(method_entry.getKey()))) {
differ.add(entry.getKey() + "." + method_entry.getKey());
logger.debug("Found other difference: " + entry.getKey());
// logger.info("Coverage difference on : "+entry.getKey()+":"+method_entry.getKey());
}
}
}
}
}
return differ;
}
/**
* Compare two coverage maps
*
* @param orig
* @param mutant
* @return unique number of methods with coverage difference
*/
private int getCoverageDifference(
Map>> orig,
Map>> mutant) {
Set differ = getDifference(orig, mutant);
differ.addAll(getDifference(mutant, orig));
return differ.size();
}
private double getSumDistance(ExecutionTrace orig_trace, ExecutionTrace mutant_trace) {
// TODO: Also sum up differences in branch distances as part of impact!
// double sum = getCoverageDifference(getCoverage(orig_trace),
// getCoverage(mutant_trace));
logger.debug("Calculating coverage impact");
double coverage_impact = getCoverageDifference(orig_trace.getCoverageData(),
mutant_trace.getCoverageData());
logger.debug("Coverage impact: " + coverage_impact);
logger.debug("Calculating data impact");
double data_impact = getCoverageDifference(orig_trace.getReturnData(),
mutant_trace.getReturnData());
logger.debug("Data impact: " + data_impact);
double branch_impact = 0.0;
for (Integer predicate : orig_trace.getCoveredPredicates()) {
if (mutant_trace.hasTrueDistance(predicate)) {
branch_impact += normalize(Math.abs(orig_trace.getTrueDistance(predicate)
- mutant_trace.getTrueDistance(predicate)));
} else {
branch_impact += 1.0;
}
if (mutant_trace.hasFalseDistance(predicate)) {
branch_impact += normalize(Math.abs(orig_trace.getFalseDistance(predicate)
- mutant_trace.getFalseDistance(predicate)));
} else {
branch_impact += 1.0;
}
}
logger.debug("Branch impact: " + branch_impact);
return normalize(coverage_impact) + normalize(data_impact) + branch_impact;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private int getNumAssertions(ExecutionResult origResult,
ExecutionResult mutant_result) {
int num = 0;
if (origResult.test.size() == 0) {
logger.debug("Orig test is empty?");
return 0;
}
for (Class> observerClass : observerClasses) {
OutputTrace trace = mutant_result.getTrace(observerClass);
OutputTrace orig = origResult.getTrace(observerClass);
if (orig == null) {
String msg = "No trace for " + observerClass + ". Traces: ";
for (OutputTrace t : origResult.getTraces())
msg += " " + t.toString();
logger.error(msg);
} else {
num += orig.numDiffer(trace);
}
}
logger.debug("Found " + num + " assertions!");
return num;
}
private void ensureExecutionResultHasTraces(TestChromosome individual, ExecutionResult result) {
if(result.getTraces().isEmpty() && observerClasses.length > 0) {
ExecutionResult newResult = runTest(individual.getTestCase());
for(Class> observerClass : observerClasses) {
OutputTrace> trace = newResult.getTrace(observerClass);
result.setTrace(trace, observerClass);
}
}
}
/* (non-Javadoc)
* @see org.evosuite.testcase.TestFitnessFunction#getFitness(org.evosuite.testcase.TestChromosome, org.evosuite.testcase.ExecutionResult)
*/
/** {@inheritDoc} */
@Override
public double getFitness(TestChromosome individual, ExecutionResult result) {
// impact (0..1)
// asserted: 0/1
//
// If not touched, fitness = branchcoveragefitnesses + 2
// If executed, fitness = normalize(constraint distance) + asserted_yes_no
// If infected, check impact?
double fitness = 0.0;
double executionDistance = diameter;
// Get control flow distance
if (!result.getTrace().getTouchedMutants().contains(mutation.getId()))
executionDistance = normalize(getExecutionDistance(result));
else
executionDistance = 0.0;
double infectionDistance = 1.0;
double impactDistance = 1.0;
boolean exceptionCase = false;
// If executed...but not with reflection
if (executionDistance <= 0 && !result.calledReflection()) {
// Add infection distance
assert (result.getTrace() != null);
// assert (result.getTrace().mutantDistances != null);
assert (result.getTrace().getTouchedMutants().contains(mutation.getId()));
infectionDistance = normalize(result.getTrace().getMutationDistance(mutation.getId()));
logger.debug("Infection distance for mutation = " + infectionDistance);
// Don't re-execute on the mutant if we believe the mutant causes timeouts
if (MutationTimeoutStoppingCondition.isDisabled(mutation) && infectionDistance <= 0) {
impactDistance = 0.0;
}
// If infected check if it is also killed
else if (infectionDistance <= 0) {
// If the trace was generated without observers, we need to re-execute
ensureExecutionResultHasTraces(individual, result);
logger.debug("Running test on mutant " + mutation.getId());
MutationExecutionResult mutationResult = individual.getLastExecutionResult(mutation);
if (mutationResult == null) {
ExecutionResult exResult = runTest(individual.getTestCase(), mutation);
mutationResult = getMutationResult(result, exResult);
individual.setLastExecutionResult(mutationResult, mutation);
}
if (mutationResult.hasTimeout()) {
logger.debug("Found timeout in mutant!");
MutationTimeoutStoppingCondition.timeOut(mutation);
fitness = 0.0; // Timeout = dead
exceptionCase = true;
}
if (mutationResult.hasException()) {
logger.debug("Mutant raises exception");
if(result.noThrownExceptions()) {
fitness = 0.0; // Exception difference
exceptionCase = true;
}
}
if (mutationResult.getNumAssertions() == 0) {
double impact = mutationResult.getImpact();
logger.debug("Impact is " + impact + " (" + (1.0 / (1.0 + impact))
+ ")");
impactDistance = 1.0 / (1.0 + impact);
} else {
logger.debug("Assertions: " + mutationResult.getNumAssertions());
impactDistance = 0.0;
}
logger.debug("Impact distance for mutation = " + fitness);
}
}
if(!exceptionCase)
fitness = impactDistance + infectionDistance + executionDistance;
logger.debug("Individual fitness: " + impactDistance + " + " + infectionDistance
+ " + " + executionDistance + " = " + fitness);
//if (fitness == 0.0) {
// assert (getNumAssertions(individual.getLastExecutionResult(),
// individual.getLastExecutionResult(mutation)) > 0);
//}
updateIndividual(this, individual, fitness);
if (fitness == 0.0) {
individual.getTestCase().addCoveredGoal(this);
//assert(isCovered(individual, result));
}
assert(fitness >= 0.0);
assert(fitness <= executionDistance + 2.0);
if (Properties.TEST_ARCHIVE) {
Archive.getArchiveInstance().updateArchive(this, individual, fitness);
}
return fitness;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
/** {@inheritDoc} */
@Override
public String toString() {
return "Strong " + mutation.toString();
}
@Override
public boolean isCovered(TestChromosome individual, ExecutionResult result) {
boolean covered = false;
if (individual.getLastExecutionResult(mutation) == null) {
covered = getFitness(individual, result) == 0.0;
}
if (!covered && individual.getLastExecutionResult(mutation) != null) {
MutationExecutionResult mutantResult = individual.getLastExecutionResult(mutation);
if (mutantResult.hasTimeout()) {
covered = true;
}
else if (mutantResult.hasException() && result.noThrownExceptions()) {
covered = true;
}
else if (mutantResult.getNumAssertions() > 0) {
covered = true;
}
}
return covered;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy