All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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