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

org.evosuite.testsuite.similarity.DiversityObserver Maven / Gradle / Ivy

/**
 * 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.similarity;

import org.evosuite.ga.Chromosome;
import org.evosuite.ga.metaheuristics.GeneticAlgorithm;
import org.evosuite.ga.metaheuristics.SearchListener;
import org.evosuite.rmi.ClientServices;
import org.evosuite.statistics.RuntimeVariable;
import org.evosuite.testcase.DefaultTestCase;
import org.evosuite.testcase.TestCase;
import org.evosuite.testcase.statements.*;
import org.evosuite.testsuite.TestSuiteChromosome;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Created by gordon on 18/12/2015.
 */
public class DiversityObserver implements SearchListener {

    private static final Logger logger = LoggerFactory.getLogger(DiversityObserver.class);

    @Override
    public void iteration(GeneticAlgorithm algorithm) {
        List individuals = (List) algorithm.getPopulation();
        double diversity = 0.0;
        int numComparisons = 0;
        for(int i = 0; i < individuals.size() - 1; i++) {
            for(int j = i+1; j < individuals.size(); j++) {
                double pairDiversity = getSuiteSimilarity(individuals.get(i), individuals.get(j));
                logger.debug("Adding diversity of pair "+i+", "+j+" of "+pairDiversity);
                diversity += pairDiversity;
                numComparisons += 1;
            }
        }
        diversity = 1.0 - diversity/numComparisons;
        logger.info("Resulting diversity for "+numComparisons +" pairs: "+diversity);
        ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.DiversityTimeline, diversity);

    }

    public static final int GAP_PENALTY = -2;

    /**
     * Naive similarity comparison between suites simply consists of merging all tests to a single test
     * for each suite, and then comparing these tests
     *
     * @param suite1
     * @param suite2
     * @return
     */
    public static double getSuiteSimilarity(TestSuiteChromosome suite1, TestSuiteChromosome suite2) {
        TestCase test1 = new DefaultTestCase();
        for(TestCase test : suite1.getTests()) {
            for(Statement s : test) {
                // These are not valid tests as the variables still point to the original test
                // but that doesn't matter as we're not executing the test
                test1.addStatement(s);
            }
        }
        TestCase test2 = new DefaultTestCase();
        for(TestCase test : suite2.getTests()) {
            for(Statement s : test) {
                test2.addStatement(s);
            }
        }

        return getNeedlemanWunschScore(test1, test2);
    }

    // TODO: Similarity based on vectors of types of calls

    /**
     * Sequence alignment based distance
     * @param test1
     * @param test2
     * @return
     */
    public static double getNeedlemanWunschScore(TestCase test1, TestCase test2) {
        int[][] matrix = new int[test1.size()+1][test2.size()+1];

        for(int i = 0; i <= test1.size(); i++)
            matrix[i][0] = GAP_PENALTY * i;

        for(int i = 0; i <= test2.size(); i++)
            matrix[0][i] = GAP_PENALTY * i;

        for(int x = 1; x <= test1.size(); x++) {
            for(int y = 1; y <= test2.size(); y++) {
                int upLeft = matrix[x-1][y-1] + getStatementSimilarity(test1.getStatement(x-1), test2.getStatement(y-1));
                int insert = matrix[x-1][y] + GAP_PENALTY;
                int delete = matrix[x][y-1] + GAP_PENALTY;
                matrix[x][y]= Math.max(upLeft, Math.max(delete, insert));
            }
        }
//        printMatrix(matrix);

        // Normalize
        double max = Math.max(test1.size(), test2.size()) * Math.abs(GAP_PENALTY); // max +
        if(max == 0.0) {
            return 0.0;
        }
        return matrix[test1.size()][test2.size()] / max;
    }

    // matches are given +1, mismatches are given -
    private static int getStatementSimilarity(Statement s1, Statement s2) {
        int similarity = 0;
        if(s1.getClass() == s2.getClass()) {
            similarity += 1;
            if(s1 instanceof ConstructorStatement) {
                if(getUnderlyingType((ConstructorStatement) s1).equals(getUnderlyingType((ConstructorStatement) s2)))
                    similarity += 1;
            } else if(s1 instanceof PrimitiveStatement) {
                if(getUnderlyingType((PrimitiveStatement) s1).equals(getUnderlyingType((PrimitiveStatement) s2)))
                    similarity += 1;
            } else if(s1 instanceof MethodStatement) {
                if(getUnderlyingType((MethodStatement) s1).equals(getUnderlyingType((MethodStatement) s2)))
                    similarity += 1;
            } else if(s1 instanceof FieldStatement) {
                if(getUnderlyingType((FieldStatement) s1).equals(getUnderlyingType((FieldStatement) s2)))
                    similarity += 1;
            }
            // TOOD: If underlying type is the same, further benefit
        }
        else {
            similarity = -2;
        }

        return similarity;
    }

    private static Class getUnderlyingType(ConstructorStatement cs) {
        return cs.getReturnClass();
    }

    private static Class getUnderlyingType(MethodStatement ms) {
        return ms.getMethod().getDeclaringClass();
    }

    private static Class getUnderlyingType(FieldStatement fs) {
        return fs.getField().getDeclaringClass();
    }

    private static Class getUnderlyingType(PrimitiveStatement ps) {
        return ps.getReturnClass();
    }


    public static void printMatrix(int[][] matrix) {
        for(int x = 0; x < matrix.length; x++) {
            for(int y = 0; y < matrix[x].length; y++) {
                System.out.print(" "+matrix[x][y]);
            }
            System.out.println();
        }
    }

    @Override
    public void searchStarted(GeneticAlgorithm algorithm) {

    }

    @Override
    public void searchFinished(GeneticAlgorithm algorithm) {

    }

    @Override
    public void fitnessEvaluation(Chromosome individual) {

    }

    @Override
    public void modification(Chromosome individual) {

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy