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

eu.stamp_project.diff_test_selection.DiffTestSelection Maven / Gradle / Ivy

package eu.stamp_project.diff_test_selection;

import eu.stamp_project.diff_test_selection.configuration.Configuration;
import eu.stamp_project.diff_test_selection.coverage.Coverage;
import eu.stamp_project.diff_test_selection.report.CSVReport;
import gumtree.spoon.AstComparator;
import gumtree.spoon.diff.Diff;
import gumtree.spoon.diff.operations.Operation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtStatement;
import spoon.reflect.declaration.CtElement;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.*;

/**
 * created by Benjamin DANGLOT
 * [email protected]
 * on 01/02/19
 */
public class DiffTestSelection {

    private static final Logger LOGGER = LoggerFactory.getLogger(DiffTestSelection.class);

    private Map>>> mapCoverage;

    private Coverage coverage;

    private Configuration configuration;

    public DiffTestSelection(Configuration configuration,
                             Map>>> mapCoverage) {
        this.configuration = configuration;
        this.mapCoverage = mapCoverage;
        this.coverage = new Coverage();
    }

    public Coverage getCoverage() {
        return this.coverage;
    }

    Map> getTestThatExecuteChanges() {
        final Map> testMethodPerTestClasses = new LinkedHashMap<>();
        String[] lines = configuration.diff.split(System.getProperty("line.separator"));
        for (int i = 0; i < lines.length; i++) {
            String currentLine = lines[i];
            if ((currentLine.startsWith("+++") || currentLine.startsWith("---")) &&
                    !getJavaFile(currentLine).isEmpty()) {
                Map> modifiedLinesPerQualifiedName =
                        getModifiedLinesPerQualifiedName(currentLine, lines[++i]);
                if (modifiedLinesPerQualifiedName == null) {
                    continue;
                }
                //this.coverage.addModifiedLines(modifiedLinesPerQualifiedName);
                Map> matchedChangedWithCoverage = matchChangedWithCoverage(this.mapCoverage, modifiedLinesPerQualifiedName);
                matchedChangedWithCoverage.keySet().forEach(key -> {
                    if (!testMethodPerTestClasses.containsKey(key)) {
                        testMethodPerTestClasses.put(key, matchedChangedWithCoverage.get(key));
                    } else {
                        testMethodPerTestClasses.get(key).addAll(matchedChangedWithCoverage.get(key));
                    }
                });
            }
        }
        return testMethodPerTestClasses;
    }

    private String getJavaFile(String currentLine) {
        for (String item : currentLine.split(" ")) {
            if (item.endsWith(".java")) {
                return item;
            }
            for (String value : item.split("\t")) {
                if (value.endsWith(".java")) {
                    return value;
                }
            }
        }
        return "";
    }

    private Map> matchChangedWithCoverage(Map>>> coverage,
                                                              Map> modifiedLinesPerQualifiedName) {
        Map> testClassNamePerTestMethodNamesThatCoverChanges = new LinkedHashMap<>();
        for (String testClassKey : coverage.keySet()) {
            for (String testMethodKey : coverage.get(testClassKey).keySet()) {
                for (String targetClassName : coverage.get(testClassKey).get(testMethodKey).keySet()) {
                    if (modifiedLinesPerQualifiedName.containsKey(targetClassName)) {
                        for (Integer line : modifiedLinesPerQualifiedName.get(targetClassName)) {
                            if (coverage.get(testClassKey).get(testMethodKey).get(targetClassName).contains(line)) {
                                // testClassKey#testMethodKey hits targetClassName#line
                                this.coverage.covered(targetClassName, line);
                                if (!testClassNamePerTestMethodNamesThatCoverChanges.containsKey(testClassKey)) {
                                    testClassNamePerTestMethodNamesThatCoverChanges.put(testClassKey, new HashSet<>());
                                }
                                testClassNamePerTestMethodNamesThatCoverChanges.get(testClassKey).add(testMethodKey);
                            }
                        }
                    }
                }
            }
        }
        return testClassNamePerTestMethodNamesThatCoverChanges;
    }

    private Map> getModifiedLinesPerQualifiedName(String currentLine,
                                                                        String secondLine) {
        final File baseDir = new File(this.configuration.pathToFirstVersion);
        final String file1 = getCorrectPathFile(currentLine);
        final String file2 = getCorrectPathFile(secondLine);
        if (shouldSkip(file1, file2)) {
            LOGGER.warn("Could not match " + file1 + " and " + file2);
            return null;
        }
        final File f1 = getCorrectFile(baseDir.getAbsolutePath(), file1);
        final File f2 = getCorrectFile(this.configuration.pathToSecondVersion, file2);
        try {
            LOGGER.info(f1.getAbsolutePath());
            LOGGER.info(f2.getAbsolutePath());
            return buildMap(new AstComparator().compare(f1, f2));
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("Error when trying to compare " + f1 + " and " + f2);
            return null;
        }
    }

    private boolean shouldSkip(String file1, String file2) {
        if (file2.endsWith(file1)) {
            return false;
        }
        if (new File(file1).isAbsolute() && new File(file2).isAbsolute() &&
                file2.endsWith(file1.substring(this.configuration.pathToFirstVersion.length()))) {
            return false;
        }
        LOGGER.warn("Could not match " + file1 + " and " + file2);
        return true;
    }

    @NotNull
    private Map> buildMap(Diff compare) {
        Map> modifiedLinesPerQualifiedName = new LinkedHashMap<>();// keeps the order
        final List allOperations = compare.getAllOperations();
        final List statements = new ArrayList<>();
        for (Operation operation : allOperations) {
            final CtElement node = filterOperation(operation);
            if (node != null && !statements.contains(node.getParent(CtStatement.class))) {
                final int line = node.getPosition().getLine();
                final String qualifiedName = node
                        .getPosition()
                        .getCompilationUnit()
                        .getMainType()
                        .getQualifiedName();
                if (!modifiedLinesPerQualifiedName.containsKey(qualifiedName)) {
                    modifiedLinesPerQualifiedName.put(qualifiedName, new ArrayList<>());
                }
                modifiedLinesPerQualifiedName.get(qualifiedName).add(line);
                if (!(node.getParent(CtStatement.class) instanceof CtBlock)) {
                    this.coverage.addModifiedLine(qualifiedName, line);
                }
                statements.add(node.getParent(CtStatement.class));
            }
        }
        return modifiedLinesPerQualifiedName;
    }

    /*
        UTILS METHODS
     */

    private CtElement filterOperation(Operation operation) {
        if (operation.getSrcNode() != null &&
                filterOperationFromNode(operation.getSrcNode())) {
            return operation.getSrcNode();
        } else if (operation.getDstNode() != null &&
                filterOperationFromNode(operation.getDstNode())) {
            return operation.getDstNode();
        }
        return null;
    }

    private boolean filterOperationFromNode(CtElement element) {
        return element.getPosition() != null &&
                element.getPosition().getCompilationUnit() != null &&
                element.getPosition().getCompilationUnit().getMainType() != null;
    }

    private File getCorrectFile(String baseDir, String fileName) {
        File file = new File(fileName);
        if (file.isAbsolute() && file.exists()) {
            return file;
        }
        if (fileName.substring(1).startsWith(this.configuration.module)) {
            fileName = fileName.substring(this.configuration.module.length() + 1);
        }
        file = new File(baseDir + "/" + fileName);
        return file.exists() ? file : new File(baseDir + "/../" + fileName);
    }

    private String getCorrectPathFile(String path) {
        return removeDiffPrefix(getJavaFile(path));
    }

    private String removeDiffPrefix(String s) {
        return s.startsWith("a") || s.startsWith("b") ? s.substring(1) : s;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy