org.evosuite.regression.RegressionSuiteFitness 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.regression;
import static org.evosuite.Properties.REGRESSION_ANALYSIS_OBJECTDISTANCE;
import static org.evosuite.regression.RegressionFitnessHelper.useMeasure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.evosuite.Properties;
import org.evosuite.TestGenerationContext;
import org.evosuite.coverage.branch.Branch;
import org.evosuite.coverage.branch.BranchCoverageSuiteFitness;
import org.evosuite.coverage.branch.BranchPool;
import org.evosuite.testcase.ExecutableChromosome;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.execution.ExecutionTracer;
import org.evosuite.testcase.execution.MethodCall;
import org.evosuite.testcase.execution.TestCaseExecutor;
import org.evosuite.testsuite.AbstractTestSuiteChromosome;
import org.evosuite.testsuite.TestSuiteFitnessFunction;
public class RegressionSuiteFitness extends TestSuiteFitnessFunction {
/**
*
*/
private static final long serialVersionUID = -1979463801167353053L;
private Map> diversityMap = new HashMap<>();
private int maxBranchFitnessValueO = 0;
private int maxBranchFitnessValueR = 0;
private Map branchIdMap = new HashMap<>();
private transient RegressionExecutionObserver observer;
private BranchCoverageSuiteFitness bcFitness;
private BranchCoverageSuiteFitness bcFitnessRegression;
private Map branchDistanceMap;
private double bestFitness = Double.MAX_VALUE;
private HashMap tempBranchDistanceMap;
private int uniqueCalls;
public RegressionSuiteFitness() {
super();
logger.warn("### initialising Regression-GA... ###");
initBranchMap();
try {
TestGenerationContext.getInstance().getRegressionClassLoaderForSUT()
.loadClass(Properties.TARGET_CLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// init branch coverage fitness
bcFitness = new BranchCoverageSuiteFitness();
bcFitnessRegression = new BranchCoverageSuiteFitness(
TestGenerationContext.getInstance().getRegressionClassLoaderForSUT());
// set branch coverage max values
maxBranchFitnessValueO = bcFitness.getMaxValue();
maxBranchFitnessValueR = bcFitnessRegression.getMaxValue();
observer = new RegressionExecutionObserver();
ExecutionTracer.enableTraceCalls();
}
private void initBranchMap() {
// populate a temp branch distance map with initial data for all
// branches(if they are not covered, 4 will be considered).
tempBranchDistanceMap = new HashMap<>();
double maxBranchValue = 4.0;
for (Branch b : BranchPool
.getInstance(TestGenerationContext.getInstance().getClassLoaderForSUT()).getAllBranches()) {
tempBranchDistanceMap.put(b.getActualBranchId(), maxBranchValue);
}
}
private void executeChangedTestsAndUpdateResults(
AbstractTestSuiteChromosome extends ExecutableChromosome> changedSuite) {
observer.clearPools();
diversityMap.clear();
RegressionTestSuiteChromosome suite = (RegressionTestSuiteChromosome) changedSuite;
for (TestChromosome chromosome : suite.getTestChromosomes()) {
RegressionTestChromosome c = (RegressionTestChromosome) chromosome;
observer.enable();
observer.resetObjPool();
observer.setRegressionFlag(false);
TestChromosome testChromosome = c.getTheTest();
TestChromosome otherChromosome = c.getTheSameTestForTheOtherClassLoader();
// Only execute test if it hasn't been changed
if (testChromosome.isChanged() || testChromosome.getLastExecutionResult() == null) {
// record diversity
if (Properties.REGRESSION_DIVERSITY) {
RegressionFitnessHelper.trackDiversity(c, testChromosome);
}
ExecutionResult result = TestCaseExecutor.runTest(testChromosome.getTestCase());
observer.setRegressionFlag(true);
ExecutionResult otherResult = TestCaseExecutor.runTest(otherChromosome.getTestCase());
observer.setRegressionFlag(false);
observer.disable();
double objectDistance = getTestObjectDistance(
observer.currentObjectMapPool,
observer.currentRegressionObjectMapPool);
result.regressionObjectDistance = objectDistance;
otherResult.regressionObjectDistance = objectDistance;
testChromosome.setLastExecutionResult(result);
testChromosome.setChanged(false);
otherChromosome.setLastExecutionResult(otherResult);
otherChromosome.setChanged(false);
}
if (Properties.REGRESSION_DIVERSITY) {
measureDiversity(c);
}
}
}
private void measureDiversity(RegressionTestChromosome c) {
for (Entry> dEntry : c.diversityMap.entrySet()) {
Map divInstance = diversityMap.get(dEntry.getKey());
if (divInstance == null) {
diversityMap.put(dEntry.getKey(), dEntry.getValue());
} else {
Map testMethodCalls = dEntry.getValue();
for (Entry mc : testMethodCalls.entrySet()) {
String calls = divInstance.get(mc.getKey());
if (calls == null || calls.length() < mc.getValue().length()) {
calls = mc.getValue();
}
divInstance.put(mc.getKey(), calls);
}
}
}
}
/*
* Get fitness value for individual
*
* @see org.evosuite.ga.FitnessFunction#getFitness(org.evosuite.ga.Chromosome)
*/
@Override
public double getFitness(AbstractTestSuiteChromosome extends ExecutableChromosome> individual) {
if (useMeasure(RegressionMeasure.STATE_DIFFERENCE)) {
TestCaseExecutor.getInstance().addObserver(observer);
observer.clearPools();
}
double distance = 0.0;
double fitness = 0.0;
// populate branches with a value of 2 (branch not covered yet)
// branchDistanceMap = new HashMap();
branchDistanceMap = (Map) tempBranchDistanceMap.clone();
int numDifferentExceptions = 0;
int totalExceptions = 0;
executeChangedTestsAndUpdateResults(individual);
RegressionTestSuiteChromosome suite = (RegressionTestSuiteChromosome) individual;
List objectDistances = new ArrayList<>();
for (TestChromosome regressionTest : suite.getTestChromosomes()) {
RegressionTestChromosome rtc = (RegressionTestChromosome) regressionTest;
ExecutionResult result1 = rtc.getTheTest().getLastExecutionResult();
ExecutionResult result2 = rtc.getTheSameTestForTheOtherClassLoader().getLastExecutionResult();
// calculating exception difference
int numExceptionOrig = result1.getNumberOfThrownExceptions();
int numExceptionReg = result2.getNumberOfThrownExceptions();
double exDiff = Math.abs((double) (numExceptionOrig - numExceptionReg));
totalExceptions += numExceptionOrig + numExceptionReg;
numDifferentExceptions += exDiff;
// branch distance
if (useMeasure(RegressionMeasure.BRANCH_DISTANCE)) {
this.getBranchDistance(
result1.getTrace().getMethodCalls(),
result2.getTrace().getMethodCalls());
}
// object distance
objectDistances.add(result1.regressionObjectDistance);
}
double objectDistanceFitness = 0;
if (useMeasure(RegressionMeasure.STATE_DIFFERENCE)) {
if (!objectDistances.isEmpty()) {
distance = Collections.max(objectDistances);
}
objectDistanceFitness =
(1.0 / (1.0 + distance)) * (maxBranchFitnessValueO + maxBranchFitnessValueR);
}
AbstractTestSuiteChromosome testSuiteChromosome = suite.getTestSuite();
AbstractTestSuiteChromosome testRegressionSuiteChromosome = null;
if (useMeasure(RegressionMeasure.COVERAGE_NEW)) {
testRegressionSuiteChromosome = suite.getTestSuiteForTheOtherClassLoader();
}
double coverageOld = 0, coverageNew = 0;
if (useMeasure(RegressionMeasure.COVERAGE_OLD)) {
coverageOld = bcFitness.getFitness(testSuiteChromosome);
}
if (useMeasure(RegressionMeasure.COVERAGE_NEW)) {
coverageNew = bcFitnessRegression.getFitness(testRegressionSuiteChromosome);
}
double coverage = coverageOld + coverageNew;
double branchDistanceFitness = 0;
double totalBranchDistanceFitness = 0.0;
if (useMeasure(RegressionMeasure.BRANCH_DISTANCE)) {
for (Map.Entry branch : branchDistanceMap.entrySet()) {
totalBranchDistanceFitness += branch.getValue();
}
branchDistanceFitness = totalBranchDistanceFitness;
}
switch (Properties.REGRESSION_FITNESS) {
case COVERAGE_OLD:
fitness += coverageOld;
break;
case COVERAGE_NEW:
fitness += coverageNew;
break;
case BRANCH_DISTANCE:
fitness += branchDistanceFitness;
break;
case STATE_DIFFERENCE:
fitness += objectDistanceFitness;
break;
case COVERAGE:
fitness += coverage;
break;
case ALL_MEASURES:
default:
fitness += coverage;
fitness += branchDistanceFitness;
fitness += objectDistanceFitness;
break;
}
double exceptionDistance = (1.0 / (1.0 + numDifferentExceptions));
fitness += exceptionDistance;
if (Properties.REGRESSION_DIVERSITY) {
calculateDiversity();
double diversityFitness = (1.0 / (1.0 + uniqueCalls));
fitness += diversityFitness;
}
individual.setCoverage(this, (bcFitness.totalCovered + bcFitnessRegression.totalCovered) / 2.0);
updateIndividual(this, individual, fitness);
if (fitness < bestFitness) {
bestFitness = fitness;
logger.warn("OBJ distance: " + distance + " - fitness:" + fitness + " - branchDistance:"
+ totalBranchDistanceFitness + " - coverage:" + coverage + " - ex: "
+ numDifferentExceptions + " - tex: " + totalExceptions);
logger.warn("Best Fitness " + fitness + ", number of tests: " + testSuiteChromosome.size()
+ ", total length: " + testSuiteChromosome.totalLengthOfTestCases());
}
return fitness;
}
/**
* Calculate diversity among objects
*/
private void calculateDiversity() {
// LRS lrs = new LRS();
uniqueCalls = 0;
for (Entry> dEntry : diversityMap.entrySet()) {
Map calleeObjects = diversityMap.get(dEntry.getKey());
for (Entry mCall : calleeObjects.entrySet()) {
boolean alreadyPresent = false;
for (int position : calleeObjects.keySet()) {
if (position != mCall.getKey()
&& calleeObjects.get(position).contains(mCall.getValue())) {
alreadyPresent = true;
break;
}
}
if (!alreadyPresent) {
uniqueCalls++;
}
}
}
}
/*
* Get the distance of two branches given two method calls
*
* @deprecated This function isn't in use anymore...
*/
private void getBranchDistance(List methodCallsOrig,
List methodCallsReg) {
/*
* Here's how this method works:
*
* It takes two pointers i and j, and two lists of method calls
*
* Then for each of the equal methods: - it takes two sets of branch traces and two pointers k
* and l - it then compares the branch distances
*
* The pointers skip forward if one side is not equal to the other (possibly to skip new code
* that was added)
*/
for (int i = 0, j = 0; i < methodCallsOrig.size() && j < methodCallsReg.size(); ) {
MethodCall mO = methodCallsOrig.get(i);
MethodCall mR = methodCallsReg.get(j);
if (mO.methodName.equals(mR.methodName)) {
// logger.warn("mO is mR: " + mO.methodName);
List branchesO = mO.branchTrace;
List branchesR = mR.branchTrace;
for (int k = 0, l = 0; k < branchesO.size() && l < branchesR.size(); ) {
Integer branchO = branchesO.get(k);
Integer branchR = branchesR.get(l);
if (Properties.REGRESSION_DIFFERENT_BRANCHES) {
logger.error(
"Regression_differrent_branches has been deprecated and removed from Evosuite. Please disable the property and try again");
if (branchIdMap.containsKey(branchO)) {
branchR = branchIdMap.get(branchO);
} else {
if ((Objects.equals(branchO, branchR))) {
k++;
}
l++;
continue;
}
}
if (Objects.equals(branchO, branchR)) {
double trueDisO = normalize(mO.trueDistanceTrace.get(k));
double trueDisR = normalize(mR.trueDistanceTrace.get(l));
double falseDisO = normalize(mO.falseDistanceTrace.get(k));
double falseDisR = normalize(mR.falseDistanceTrace.get(l));
double tempBranchDistance =
2.0 * (1 - (Math.abs(trueDisO - trueDisR) + Math.abs(falseDisO - falseDisR)));
tempBranchDistance += (Math.abs(trueDisR) + Math.abs(falseDisR)) / 2.0;
tempBranchDistance += (Math.abs(trueDisO) + Math.abs(falseDisO)) / 2.0;
if ((trueDisO == 0 && falseDisR == 0) || (falseDisO == 0 && trueDisR == 0)) {
tempBranchDistance = 0;
}
if (!branchDistanceMap.containsKey(branchO)
|| branchDistanceMap.get(branchO) > tempBranchDistance) {
branchDistanceMap.put(branchO, tempBranchDistance);
}
k++;
l++;
continue;
} else {
break;
}
}
i++;
j++;
continue;
} else if (mO.callDepth == 1 && mR.callDepth > 1) {
j++;
continue;
} else if (mR.callDepth == 1 && mO.callDepth > 1) {
i++;
continue;
} else {
i++;
j++;
}
}
}
private double getTestObjectDistance(
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy