![JAR search and dependency download from the Maven repository](/logo.png)
org.evosuite.testsuite.localsearch.DeprecatedTestSuiteDSE 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.testsuite.localsearch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.Map.Entry;
import org.evosuite.Properties;
import org.evosuite.ga.Chromosome;
import org.evosuite.ga.FitnessFunction;
import org.evosuite.ga.localsearch.LocalSearchBudget;
import org.evosuite.ga.localsearch.LocalSearchObjective;
import org.evosuite.symbolic.BranchCondition;
import org.evosuite.symbolic.ConcolicExecution;
import org.evosuite.symbolic.DSEStats;
import org.evosuite.symbolic.expr.Comparator;
import org.evosuite.symbolic.expr.Constraint;
import org.evosuite.symbolic.expr.Expression;
import org.evosuite.symbolic.expr.Variable;
import org.evosuite.symbolic.solver.Solver;
import org.evosuite.symbolic.solver.SolverCache;
import org.evosuite.symbolic.solver.SolverFactory;
import org.evosuite.symbolic.solver.SolverResult;
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.localsearch.DSETestCaseLocalSearch;
import org.evosuite.testcase.localsearch.TestCaseLocalSearch;
import org.evosuite.testcase.statements.PrimitiveStatement;
import org.evosuite.testcase.statements.Statement;
import org.evosuite.testsuite.TestSuiteChromosome;
import org.evosuite.testsuite.TestSuiteFitnessFunction;
import org.evosuite.utils.Randomness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Deprecated
public class DeprecatedTestSuiteDSE {
private static final Logger logger = LoggerFactory.getLogger(DeprecatedTestSuiteDSE.class);
/** Constant nrConstraints=0
*/
private static int nrConstraints = 0;
/** Constant nrSolvedConstraints=0
*/
private static int nrSolvedConstraints = 0;
private int nrCurrConstraints = 0;
/** Constant success=0
*/
private static int success = 0;
/** Constant failed=0
*/
private static int failed = 0;
private LocalSearchObjective objective;
private static class Branch {
public Branch(int branchIndex, boolean isTrueBranch) {
super();
this.branchIndex = branchIndex;
this.isTrueBranch = isTrueBranch;
}
private int branchIndex;
private boolean isTrueBranch;
public Branch negate() {
return new Branch(branchIndex, !isTrueBranch);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + branchIndex;
result = prime * result + (isTrueBranch ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Branch other = (Branch) obj;
if (branchIndex != other.branchIndex)
return false;
if (isTrueBranch != other.isTrueBranch)
return false;
return true;
}
@Override
public String toString() {
return "Branch [branchIndex=" + branchIndex + ", isTrueBranch=" + isTrueBranch + "]";
}
}
// private final TestSuiteFitnessFunction fitness;
/**
* Stores the path condition from each test execution
*/
private final Map> pathConditions = new HashMap>();
private final Set unsolvableBranchConditions = new HashSet();
private final Map solutionAttempts = new HashMap();
private Collection unsolvedBranchConditions = null;
private class TestBranchPair implements Comparable {
TestChromosome test;
BranchCondition branch;
List pathCondition;
private final double ranking;
TestBranchPair(TestChromosome test, List pathCondition, BranchCondition branchCondition) {
this.test = test;
this.branch = branchCondition;
this.pathCondition = pathCondition;
this.ranking = computeRanking(pathCondition, branchCondition);
}
private double computeRanking(List pathCondition, BranchCondition targetBranch) {
List> reachingConstraints = new LinkedList>();
for (BranchCondition b : pathCondition) {
reachingConstraints.addAll(b.getSupportingConstraints());
reachingConstraints.add(b.getConstraint());
if (b == targetBranch) {
break;
}
}
int length = 1 + reachingConstraints.size();
int totalSize = 0;
for (Constraint> constraint : reachingConstraints) {
totalSize += constraint.getSize();
}
double avg_size = (double) totalSize / (double) reachingConstraints.size();
double ranking = length * avg_size;
return ranking;
}
@Override
public int compareTo(TestBranchPair arg0) {
return Double.compare(this.ranking, arg0.ranking);
}
}
/**
* Iterate over path constraints to identify those which map to branches
* that are only covered one way
*/
private void calculateUncoveredBranches() {
unsolvedBranchConditions.clear();
if (Properties.DSE_NEGATE_ALL_CONDITIONS == true) {
for (TestChromosome testChromosome : pathConditions.keySet()) {
final List pathCondition = pathConditions.get(testChromosome);
for (BranchCondition branch : pathCondition) {
if (!unsolvableBranchConditions.contains(branch)) {
unsolvedBranchConditions.add(new TestBranchPair(testChromosome, pathCondition, branch));
}
}
}
} else {
Map>> solvedConstraints = new HashMap>>();
for (TestChromosome test : pathConditions.keySet()) {
final List pathCondition = pathConditions.get(test);
for (BranchCondition branch : pathCondition) {
if (unsolvableBranchConditions.contains(branch))
continue;
String index = getBranchIndex(branch);
if (!solvedConstraints.containsKey(index))
solvedConstraints.put(index, new HashMap>());
Constraint> c = branch.getConstraint();
if (!solvedConstraints.get(index).containsKey(c.getComparator()))
solvedConstraints.get(index).put(c.getComparator(), new HashSet());
solvedConstraints.get(index).get(c.getComparator())
.add(new TestBranchPair(test, pathCondition, branch));
}
}
for (String index : solvedConstraints.keySet()) {
if (solvedConstraints.get(index).size() == 1) {
Set branches = solvedConstraints.get(index).values().iterator().next();
unsolvedBranchConditions.addAll(branches);
}
}
logger.info("Update set of unsolved branch conditions to " + unsolvedBranchConditions.size());
if (Properties.DSE_RANK_BRANCH_CONDITIONS == false) {
Randomness.shuffle((ArrayList) unsolvedBranchConditions);
}
}
}
/**
* Calculate and store path constraints for an individual
*
* @param test
*/
private void updatePathConstraints(TestChromosome test) {
List pathCondition = ConcolicExecution.getSymbolicPath(test);
pathConditions.put(test, pathCondition);
}
/**
* Create path constraints for all tests in a test suite
*
* @param testSuite
*/
private void createPathConstraints(TestSuiteChromosome testSuite) {
for (TestChromosome test : testSuite.getTestChromosomes()) {
updatePathConstraints(test);
}
calculateUncoveredBranches();
}
private String getBranchIndex(BranchCondition branch) {
return branch.getFullName() + branch.getInstructionIndex();
}
/**
* Get a new candidate for negation
*
* @return
*/
private TestBranchPair getNextBranchCondition() {
TestBranchPair pair;
pair = getNextTestBranchPair();
if (Properties.DSE_NEGATE_ALL_CONDITIONS == true) {
return pair;
}
String index = getBranchIndex(pair.branch);
if (!unsolvedBranchConditions.isEmpty()) {
while (solutionAttempts.containsKey(index)
&& solutionAttempts.get(index) >= Properties.CONSTRAINT_SOLUTION_ATTEMPTS
&& !unsolvedBranchConditions.isEmpty()) {
logger.info("Reached maximum number of attempts for branch " + index);
pair = getNextTestBranchPair();
index = getBranchIndex(pair.branch);
}
}
if (!solutionAttempts.containsKey(index))
solutionAttempts.put(index, 1);
else
solutionAttempts.put(index, solutionAttempts.get(index) + 1);
return pair;
}
private TestBranchPair getNextTestBranchPair() {
TestBranchPair pair;
if (Properties.DSE_RANK_BRANCH_CONDITIONS) {
pair = ((PriorityQueue) unsolvedBranchConditions).poll();
} else {
pair = ((ArrayList) unsolvedBranchConditions).remove(0);
}
return pair;
}
/**
* Check if there are further candidates for negation
*
* @return
*/
private boolean hasNextBranchCondition() {
return !unsolvedBranchConditions.isEmpty();
}
/**
* Generate new constraint and ask solver for solution
*
* @param condition
* @param test
* @return
*/
// @SuppressWarnings("rawtypes")
// @SuppressWarnings("rawtypes")
@SuppressWarnings({ "unchecked", "rawtypes" })
private TestCase negateCondition(Set> reachingConstraints, Constraint> localConstraint,
TestCase test) {
List> constraints = new LinkedList>();
constraints.addAll(reachingConstraints);
Constraint> targetConstraint = localConstraint.negate();
constraints.add(targetConstraint);
if (!targetConstraint.isSolveable()) {
logger.info("Found unsolvable constraint: " + targetConstraint);
// TODO: This is usually the case when the same variable is used for
// several parameters of a method
// Could we treat this as a special case?
return null;
}
int size = constraints.size();
/*
* int counter = 0; for (Constraint cnstr : constraints) { logger.debug(
* "Cnstr " + (counter++) + " : " + cnstr + " dist: " +
* DistanceEstimator.getDistance(constraints)); }
*/
if (size > 0) {
logger.debug("Calculating cone of influence for " + size + " constraints");
constraints = reduce(constraints);
logger.info("Reduced constraints from " + size + " to " + constraints.size());
// for (Constraint> c : constraints) {
// logger.info(c.toString());
// }
}
nrCurrConstraints = constraints.size();
nrConstraints += nrCurrConstraints;
logger.info("Applying local search");
Solver solver = SolverFactory.getInstance().buildNewSolver();
DSEStats.getInstance().reportNewConstraints(constraints);
long startSolvingTime = System.currentTimeMillis();
SolverCache solverCache = SolverCache.getInstance();
SolverResult solverResult = solverCache.solve(solver, constraints);
long estimatedSolvingTime = System.currentTimeMillis() - startSolvingTime;
DSEStats.getInstance().reportNewSolvingTime(estimatedSolvingTime);
if (solverResult == null) {
logger.info("Found no solution");
/* Timeout, parseException, error, trivialSolution, etc. */
return null;
} else if (solverResult.isUNSAT()) {
logger.info("Found UNSAT solution");
DSEStats.getInstance().reportNewUNSAT();
return null;
} else {
Map model = solverResult.getModel();
DSEStats.getInstance().reportNewSAT();
TestCase newTest = test.clone();
for (Object key : model.keySet()) {
Object val = model.get(key);
if (val != null) {
logger.info("New value: " + key + ": " + val);
if (val instanceof Long) {
Long value = (Long) val;
String name = ((String) key).replace("__SYM", "");
// logger.warn("New long value for " + name + " is " +
// value);
PrimitiveStatement p = getStatement(newTest, name);
if (p.getValue().getClass().equals(Character.class))
p.setValue((char) value.intValue());
else if (p.getValue().getClass().equals(Long.class))
p.setValue(value);
else if (p.getValue().getClass().equals(Integer.class))
p.setValue(value.intValue());
else if (p.getValue().getClass().equals(Short.class))
p.setValue(value.shortValue());
else if (p.getValue().getClass().equals(Boolean.class))
p.setValue(value.intValue() > 0);
else if (p.getValue().getClass().equals(Byte.class))
p.setValue(value.byteValue() > 0);
else
logger.warn("New value is of an unsupported type: " + p.getValue().getClass() + val);
} else if (val instanceof String) {
String name = ((String) key).replace("__SYM", "");
PrimitiveStatement p = getStatement(newTest, name);
// logger.warn("New string value for " + name + " is " +
// val);
assert (p != null) : "Could not find variable " + name + " in test: " + newTest.toCode()
+ " / Orig test: " + test.toCode() + ", seed: " + Randomness.getSeed();
if (p.getValue().getClass().equals(Character.class))
p.setValue((char) Integer.parseInt(val.toString()));
else
p.setValue(val.toString());
} else if (val instanceof Double) {
Double value = (Double) val;
String name = ((String) key).replace("__SYM", "");
PrimitiveStatement p = getStatement(newTest, name);
// logger.warn("New double value for " + name + " is " +
// value);
assert (p != null) : "Could not find variable " + name + " in test: " + newTest.toCode()
+ " / Orig test: " + test.toCode() + ", seed: " + Randomness.getSeed();
if (p.getValue().getClass().equals(Double.class))
p.setValue(value);
else if (p.getValue().getClass().equals(Float.class))
p.setValue(value.floatValue());
else
logger.warn("New value is of an unsupported type: " + val);
} else {
logger.debug("New value is of an unsupported type: " + val);
}
} else {
logger.debug("New value is null");
}
}
return newTest;
}
}
/**
* Get the statement that defines this variable
*
* @param test
* @param name
* @return
*/
private PrimitiveStatement> getStatement(TestCase test, String name) {
for (Statement statement : test) {
if (statement instanceof PrimitiveStatement>) {
if (statement.getReturnValue().getName().equals(name))
return (PrimitiveStatement>) statement;
}
}
return null;
}
/**
* Apply cone of influence reduction to constraints with respect to the last
* constraint in the list
*
* @param constraints
* @return
*/
private List> reduce(List> constraints) {
Constraint> target = constraints.get(constraints.size() - 1);
Set> dependencies = getVariables(target);
LinkedList> coi = new LinkedList>();
if (dependencies.size() <= 0)
return coi;
coi.add(target);
for (int i = constraints.size() - 2; i >= 0; i--) {
Constraint> constraint = constraints.get(i);
Set> variables = getVariables(constraint);
for (Variable> var : dependencies) {
if (variables.contains(var)) {
dependencies.addAll(variables);
coi.addFirst(constraint);
break;
}
}
}
return coi;
}
/**
* Determine the set of variable referenced by this constraint
*
* @param constraint
* @return
*/
private Set> getVariables(Constraint> constraint) {
Set> variables = new HashSet>();
getVariables(constraint.getLeftOperand(), variables);
getVariables(constraint.getRightOperand(), variables);
return variables;
}
/**
* Recursively determine constraints in expression
*
* @param expr
* a {@link org.evosuite.symbolic.expr.Expression} object.
* @param variables
* a {@link java.util.Set} object.
*/
private static void getVariables(Expression> expr, Set> variables) {
variables.addAll(expr.getVariables());
}
private double getFitness(TestSuiteChromosome suite) {
for (FitnessFunction extends Chromosome> ff : objective.getFitnessFunctions()) {
TestSuiteFitnessFunction tff = (TestSuiteFitnessFunction) ff;
tff.getFitness(suite);
}
return suite.getFitness();
}
private boolean reachesUncoveredBranch(TestChromosome test, Set uncoveredBranches) {
Set testCoveredBranches = getCoveredBranches(test);
for (Branch b : testCoveredBranches) {
Branch negate = b.negate();
if (uncoveredBranches.contains(negate)) {
return true;
}
}
return false;
}
/**
* Returns the set of all branches that are not covered both-wise
*
* @param coveredBranches
* @return
*/
private static Set getUncoveredBranches(Set coveredBranches) {
Set uncoveredBranches = new HashSet();
for (Branch b : coveredBranches) {
final Branch negate = b.negate();
if (!coveredBranches.contains(negate)) {
uncoveredBranches.add(negate);
}
}
return uncoveredBranches;
}
/**
* Returns the set covered branches by this suite
*
* @param suite
* @return
*/
private static Set getCoveredBranches(TestSuiteChromosome suite) {
final Set suiteCoveredBranches = new HashSet();
for (TestChromosome test : suite.getTestChromosomes()) {
final Set testCoveredBranches = getCoveredBranches(test);
suiteCoveredBranches.addAll(testCoveredBranches);
}
return suiteCoveredBranches;
}
/**
* Returns the set of covered branches by this test
*
* @param test
* @return
*/
private static Set getCoveredBranches(TestChromosome test) {
final Set testCoveredBranches = new HashSet();
ExecutionTrace trace = test.getLastExecutionResult().getTrace();
{
Set coveredTrueBranchIndexesInTrace = trace.getCoveredTrueBranches();
for (Integer branchIndex : coveredTrueBranchIndexesInTrace) {
Branch b = new Branch(branchIndex, true);
testCoveredBranches.add(b);
}
}
{
Set coveredFalseBranchIndexesInTrace = trace.getCoveredFalseBranches();
for (Integer branchIndex : coveredFalseBranchIndexesInTrace) {
Branch b = new Branch(branchIndex, false);
testCoveredBranches.add(b);
}
}
return testCoveredBranches;
}
/**
* Attempt to negate individual branches until budget is used up, or there
* are no further branches to negate
*
* @param individual
*/
public boolean applyDSE0(TestSuiteChromosome individual) {
logger.info("[DSE] Current test suite: " + individual.toString());
boolean wasSuccess = false;
// expansion already happens as part of LS
// TestSuiteChromosome expandedTests = expandTestSuite(individual);
TestSuiteChromosome expandedTests = individual.clone();
createPathConstraints(expandedTests);
// fitness.getFitness(expandedTests);
double originalFitness = getFitness(individual);
while (hasNextBranchCondition() && !LocalSearchBudget.getInstance().isFinished()) {
logger.info("Branches remaining: " + unsolvedBranchConditions.size());
TestBranchPair next = getNextBranchCondition();
BranchCondition branch = next.branch;
List pathCondition = next.pathCondition;
List> reachingConstraints = new LinkedList>();
for (BranchCondition b : pathCondition) {
reachingConstraints.addAll(b.getSupportingConstraints());
if (b == branch) {
break;
}
reachingConstraints.add(b.getConstraint());
}
List> constraints = new LinkedList>();
TestCase newTest = negateCondition(new HashSet>(reachingConstraints), branch.getConstraint(),
next.test.getTestCase());
if (newTest != null) {
logger.info("Found new test: " + newTest.toCode());
TestChromosome newTestChromosome = new TestChromosome();
newTestChromosome.setTestCase(newTest);
expandedTests.addTest(newTestChromosome);
if (Properties.DSE_KEEP_ALL_TESTS) {
updatePathConstraints(newTestChromosome);
calculateUncoveredBranches();
individual.addTest(newTest);
wasSuccess = true;
} else {
if (getFitness(expandedTests) < originalFitness) {
logger.info("New test improves fitness to {}", getFitness(expandedTests));
DSEStats.getInstance().reportNewTestUseful();
wasSuccess = true;
// no need to clone so we can keep executionresult
updatePathConstraints(newTestChromosome);
calculateUncoveredBranches(newTestChromosome);
individual.addTest(newTest);
originalFitness = getFitness(expandedTests);
// TODO: Cancel on fitness 0 - would need to know if
// ZeroFitness is a stopping condition
} else {
logger.info("New test does not improve fitness");
DSEStats.getInstance().reportNewTestUnuseful();
expandedTests.deleteTest(newTest);
}
}
success++;
} else {
unsolvableBranchConditions.add(branch);
failed++;
logger.info("Failed to find new test.");
}
}
logger.info("Finished DSE");
getFitness(individual); // Ensure fitness values are up to date.
LocalSearchBudget.getInstance().countLocalSearchOnTestSuite();
return wasSuccess;
}
private void calculateUncoveredBranches(TestChromosome newTestChromosome) {
if (Properties.DSE_NEGATE_ALL_CONDITIONS == true) {
final List pathCondition = pathConditions.get(newTestChromosome);
for (BranchCondition targetBranchCondition : pathCondition) {
if (!unsolvableBranchConditions.contains(targetBranchCondition)) {
unsolvedBranchConditions
.add(new TestBranchPair(newTestChromosome, pathCondition, targetBranchCondition));
}
}
} else {
calculateUncoveredBranches();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy