org.evosuite.ga.metaheuristics.mosa.AbstractMOSA Maven / Gradle / Ivy
The newest version!
/**
*
* 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.ga.metaheuristics.mosa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.evosuite.ProgressMonitor;
import org.evosuite.Properties;
import org.evosuite.Properties.Criterion;
import org.evosuite.coverage.FitnessFunctions;
import org.evosuite.coverage.branch.BranchCoverageSuiteFitness;
import org.evosuite.coverage.exception.ExceptionCoverageFactory;
import org.evosuite.coverage.exception.ExceptionCoverageHelper;
import org.evosuite.coverage.exception.ExceptionCoverageSuiteFitness;
import org.evosuite.coverage.exception.ExceptionCoverageTestFitness;
import org.evosuite.coverage.line.LineCoverageSuiteFitness;
import org.evosuite.coverage.method.MethodCoverageSuiteFitness;
import org.evosuite.coverage.mutation.StrongMutationSuiteFitness;
import org.evosuite.coverage.mutation.WeakMutationSuiteFitness;
import org.evosuite.coverage.statement.StatementCoverageSuiteFitness;
import org.evosuite.ga.Chromosome;
import org.evosuite.ga.ChromosomeFactory;
import org.evosuite.ga.ConstructionFailedException;
import org.evosuite.ga.FitnessFunction;
import org.evosuite.ga.metaheuristics.GeneticAlgorithm;
import org.evosuite.ga.metaheuristics.SearchListener;
import org.evosuite.ga.metaheuristics.mosa.comparators.MOSADominanceComparator;
import org.evosuite.ga.operators.selection.SelectionFunction;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.TestChromosome;
import org.evosuite.testcase.TestFitnessFunction;
import org.evosuite.testcase.execution.ExecutionResult;
import org.evosuite.testcase.secondaryobjectives.TestCaseSecondaryObjective;
import org.evosuite.testcase.statements.ArrayStatement;
import org.evosuite.testcase.statements.ConstructorStatement;
import org.evosuite.testcase.statements.MethodStatement;
import org.evosuite.testcase.statements.PrimitiveStatement;
import org.evosuite.testcase.statements.Statement;
import org.evosuite.testcase.statements.StringPrimitiveStatement;
import org.evosuite.testcase.variable.VariableReference;
import org.evosuite.testsuite.TestSuiteChromosome;
import org.evosuite.testsuite.TestSuiteFitnessFunction;
import org.evosuite.utils.ArrayUtil;
import org.evosuite.utils.Randomness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract class for MOSA
*
* @author Annibale Panichella, Fitsum M. Kifetew
*
* @param
*/
public abstract class AbstractMOSA extends GeneticAlgorithm {
private static final long serialVersionUID = 146182080947267628L;
private static final Logger logger = LoggerFactory.getLogger(MOSA.class);
/** keep track of overall suite fitness and coverage */
protected List suiteFitnesses;
/** Selection function to select parents */
protected SelectionFunction selectionFunction = new MOSATournamentSelection();
/** Selected ranking strategy **/
protected Ranking ranking;
/**
* Constructor
*
* @param factory
* a {@link org.evosuite.ga.ChromosomeFactory} object
*/
public AbstractMOSA(ChromosomeFactory factory) {
super(factory);
suiteFitnesses = new ArrayList();
for (Properties.Criterion criterion : Properties.CRITERION){
TestSuiteFitnessFunction fit = FitnessFunctions.getFitnessFunction(criterion);
suiteFitnesses.add(fit);
}
// set the ranking strategy
if (Properties.RANKING_TYPE == Properties.RankingType.PREFERENCE_SORTING)
ranking = new RankBasedPreferenceSorting();
else if (Properties.RANKING_TYPE == Properties.RankingType.FAST_NON_DOMINATED_SORTING)
ranking = new FastNonDominatedSorting();
else
ranking = new RankBasedPreferenceSorting(); // default ranking strategy
// set the secondary objectives of test cases (useful when MOSA compares two test
// cases to, for example, update the archive)
TestCaseSecondaryObjective.setSecondaryObjectives();
}
/**
* This method is used to generate new individuals (offsprings) from
* the current population
* @return offspring population
*/
@SuppressWarnings("unchecked")
protected List breedNextGeneration() {
List offspringPopulation = new ArrayList(Properties.POPULATION);
// we apply only Properties.POPULATION/2 iterations since in each generation
// we generate two offsprings
for (int i=0; i < Properties.POPULATION/2 && !isFinished(); i++){
// select best individuals
T parent1 = selectionFunction.select(population);
T parent2 = selectionFunction.select(population);
T offspring1 = (T) parent1.clone();
T offspring2 = (T) parent2.clone();
// apply crossover
try {
if (Randomness.nextDouble() <= Properties.CROSSOVER_RATE) {
crossoverFunction.crossOver(offspring1, offspring2);
}
} catch (ConstructionFailedException e) {
logger.debug("CrossOver failed.");
continue;
}
removeUnusedVariables(offspring1);
removeUnusedVariables(offspring2);
// apply mutation on offspring1
mutate(offspring1, parent1);
if (offspring1.isChanged()) {
clearCachedResults(offspring1);
offspring1.updateAge(currentIteration);
calculateFitness(offspring1);
offspringPopulation.add(offspring1);
}
// apply mutation on offspring2
mutate(offspring2, parent2);
if (offspring2.isChanged()) {
clearCachedResults(offspring2);
offspring2.updateAge(currentIteration);
calculateFitness(offspring2);
offspringPopulation.add(offspring2);
}
}
// Add new randomly generate tests
for (int i = 0; i to_delete = new ArrayList(chromosome.size());
boolean has_deleted = false;
int num = 0;
for (Statement s : t) {
VariableReference var = s.getReturnValue();
boolean delete = false;
delete = delete || s instanceof PrimitiveStatement;
delete = delete || s instanceof ArrayStatement;
delete = delete || s instanceof StringPrimitiveStatement;
if (!t.hasReferences(var) && delete) {
to_delete.add(num);
has_deleted = true;
}
num++;
}
Collections.sort(to_delete, Collections.reverseOrder());
for (Integer position : to_delete) {
t.remove(position);
}
int sizeAfter = chromosome.size();
if (has_deleted)
logger.debug("Removed {} unused statements", (sizeBefore - sizeAfter));
return has_deleted;
}
/**
* Notify all search listeners of fitness evaluation
*
* @param chromosome
* a {@link org.evosuite.ga.Chromosome} object.
*/
@Override
protected void notifyEvaluation(Chromosome chromosome) {
for (SearchListener listener : listeners) {
if (listener instanceof ProgressMonitor)
continue;
listener.fitnessEvaluation(chromosome);
}
}
/**
* Calculate fitness for the whole population
*/
protected void calculateFitness() {
logger.debug("Calculating fitness for " + population.size() + " individuals");
Iterator iterator = population.iterator();
while (iterator.hasNext()) {
T c = iterator.next();
if (isFinished()) {
if (c.isChanged())
iterator.remove();
} else {
calculateFitness(c);
}
}
}
@SuppressWarnings("unchecked")
@Override
public List getBestIndividuals() {
//get final test suite (i.e., non dominated solutions in Archive)
List finalTestSuite = this.getFinalTestSuite();
if (finalTestSuite.isEmpty()) {
return Arrays.asList((T) new TestSuiteChromosome());
}
TestSuiteChromosome bestTestCases = new TestSuiteChromosome();
for (T test : finalTestSuite) {
bestTestCases.addTest((TestChromosome) test);
}
for (FitnessFunction f : this.getCoveredGoals()){
bestTestCases.getCoveredGoals().add((TestFitnessFunction) f);
}
// compute overall fitness and coverage
double fitness = this.fitnessFunctions.size() - numberOfCoveredTargets();
double coverage = ((double) numberOfCoveredTargets()) / ((double) this.fitnessFunctions.size());
for (TestSuiteFitnessFunction suiteFitness : suiteFitnesses){
bestTestCases.setFitness(suiteFitness, fitness);
bestTestCases.setCoverage(suiteFitness, coverage);
bestTestCases.setNumOfCoveredGoals(suiteFitness, (int) numberOfCoveredTargets());
bestTestCases.setNumOfNotCoveredGoals(suiteFitness, (int) (this.fitnessFunctions.size()-numberOfCoveredTargets()));
}
List bests = new ArrayList(1);
bests.add((T) bestTestCases);
return bests;
}
/**
* This method computes the fitness scores only for the current goals
* @param c chromosome
*/
protected abstract void calculateFitness(T c);
protected abstract List getFinalTestSuite();
protected abstract List getArchive();
/**
* This method extracts non-dominated solutions (tests) according to all covered goal (e.g., branches)
* @param solutionSet set of test cases to analyze with the "dominance" relationship
* @return the non-dominated set of test cases
*/
protected List getNonDominatedSolutions(List solutions){
MOSADominanceComparator comparator = new MOSADominanceComparator<>(this.getCoveredGoals());
List next_front = new ArrayList(solutions.size());
boolean isDominated;
for (T p : solutions){
isDominated = false;
List dominatedSolutions = new ArrayList(solutions.size());
for (T best : next_front){
int flag = comparator.compare(p, best);
if (flag == -1) {
dominatedSolutions.add(best);
}
if (flag == +1){
isDominated = true;
}
}
if (isDominated)
continue;
next_front.add(p);
next_front.removeAll(dominatedSolutions);
}
return next_front;
}
/**
* This method verifies whether two TestCromosome contain
* the same test case. Here the equality is computed looking at
* the strings composing the tests. This method is strongly needed
* in {@link AbstractMOSA#breedNextGeneration()}.
* @param test1 first test
* @param test2 second test
* @return true if the test1 and test 2 (meant as String) are equal
* to each other; false otherwise.
*/
protected boolean areEqual(T test1, T test2){
TestChromosome tch1 = (TestChromosome) test1;
TestChromosome tch2 = (TestChromosome) test2;
if (tch1.size() != tch2.size())
return false;
if (tch1.size() == 0)
return false;
if (tch2.size() == 0)
return false;
return tch1.getTestCase().toCode().equals(tch2.getTestCase().toCode());
}
/** {@inheritDoc} */
@Override
public void initializePopulation() {
logger.info("executing initializePopulation function");
notifySearchStarted();
currentIteration = 0;
// Create a random parent population P0
generateInitialPopulation(Properties.POPULATION);
// Determine fitness
calculateFitness();
this.notifyIteration();
}
protected abstract double numberOfCoveredTargets();
public abstract Set> getCoveredGoals();
/**
* This method analyzes the execution results of a TestChromosome looking for generated exceptions.
* Such exceptions are converted in instances of the class {@link ExceptionCoverageTestFitness},
* which are additional covered goals when using as criterion {@link Properties.Criterion.EXCEPTION}
* @param t TestChromosome to analyze
* @return list of exception goals being covered by t
*/
public List deriveCoveredExceptions(T t){
List covered_exceptions = new ArrayList();
TestChromosome testCh = (TestChromosome) t;
ExecutionResult result = testCh.getLastExecutionResult();
Map>> implicitTypesOfExceptions = new LinkedHashMap<>();
Map>> explicitTypesOfExceptions = new LinkedHashMap<>();
Map>> declaredTypesOfExceptions = new LinkedHashMap<>();
for (Integer i : result.getPositionsWhereExceptionsWereThrown()) {
if(ExceptionCoverageHelper.shouldSkip(result,i)){
continue;
}
Class> exceptionClass = ExceptionCoverageHelper.getExceptionClass(result,i);
String methodIdentifier = ExceptionCoverageHelper.getMethodIdentifier(result, i); //eg name+descriptor
boolean sutException = ExceptionCoverageHelper.isSutException(result,i); // was the exception originated by a direct call on the SUT?
/*
* We only consider exceptions that were thrown by calling directly the SUT (not the other
* used libraries). However, this would ignore cases in which the SUT is indirectly tested
* through another class
*/
if (sutException) {
boolean notDeclared = ! ExceptionCoverageHelper.isDeclared(result,i);
if(notDeclared) {
/*
* we need to distinguish whether it is explicit (ie "throw" in the code, eg for validating
* input for pre-condition) or implicit ("likely" a real fault).
*/
boolean isExplicit = ExceptionCoverageHelper.isExplicit(result,i);
if (isExplicit) {
if (!explicitTypesOfExceptions.containsKey(methodIdentifier)) {
explicitTypesOfExceptions.put(methodIdentifier, new LinkedHashSet>());
}
explicitTypesOfExceptions.get(methodIdentifier).add(exceptionClass);
} else {
if (!implicitTypesOfExceptions.containsKey(methodIdentifier)) {
implicitTypesOfExceptions.put(methodIdentifier, new LinkedHashSet>());
}
implicitTypesOfExceptions.get(methodIdentifier).add(exceptionClass);
}
} else {
if (!declaredTypesOfExceptions.containsKey(methodIdentifier)) {
declaredTypesOfExceptions.put(methodIdentifier, new LinkedHashSet>());
}
declaredTypesOfExceptions.get(methodIdentifier).add(exceptionClass);
}
ExceptionCoverageTestFitness.ExceptionType type = ExceptionCoverageHelper.getType(result,i);
/*
* Add goal to list of fitness functions to solve
*/
ExceptionCoverageTestFitness goal = new ExceptionCoverageTestFitness(Properties.TARGET_CLASS, methodIdentifier, exceptionClass, type);
covered_exceptions.add(goal);
}
}
return covered_exceptions;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy