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

org.pitest.coverage.LegacyClassCoverage Maven / Gradle / Ivy

There is a newer version: 1.17.1
Show newest version
package org.pitest.coverage;

import org.pitest.bytecode.analysis.ClassTree;
import org.pitest.classinfo.ClassName;
import org.pitest.classpath.CodeSource;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Line based coverage data, used by html report and the history system
 * separated here to prevent methods being re-implemented with data
 * not available when loaded from disk for the report aggregate
 */
public class LegacyClassCoverage implements ReportCoverage {

    private final CodeSource code;
    private final Map> classesForFile;
    private final Map>> lineCoverage  = new LinkedHashMap<>();
    private final Map> blocksToLines = new LinkedHashMap<>();
    private final LineMap lm;

    public LegacyClassCoverage(CodeSource code, LineMap lm) {
        this.code = code;
        this.lm = lm;
        this.classesForFile = code.codeTrees()
                .collect(Collectors.groupingBy(keyFromClassInfo(), Collectors.mapping(tree -> new ClassLines(tree.name(), tree.codeLineNumbers()), Collectors.toList())));
    }

    public void loadBlockDataOnly(Collection coverageData) {
        addTestToClasses(new TestInfo("fake", "fakeTest",0,  Optional.empty(), 1 ),
                coverageData);
    }

    @Override
    public ClassLines getCodeLinesForClass(final ClassName clazz) {
        return code.fetchClassBytes(clazz)
                .map(ClassTree::fromBytes)
                .map(ClassLines::fromTree)
                .orElse(new ClassLines(clazz, Collections.emptySet()));
    }

    @Override
    public Set getCoveredLines(ClassName mutatedClass) {
        return  Stream.of(mutatedClass)
                .flatMap(m -> getLineCoverageForClassName(m).entrySet().stream())
                .filter(e -> !e.getValue().isEmpty())
                .map( e -> e.getKey())
                .collect(Collectors.toSet());
    }

    @Override
    public Collection getClassesForFile(String sourceFile,
                                                   String packageName) {
        return classesForFile.getOrDefault(keyFromSourceAndPackage(sourceFile, packageName), Collections.emptyList());
    }

    public Collection getTestsForClass(ClassName clazz) {
        return this.lineCoverage.getOrDefault(clazz, Collections.emptyMap()).values().stream()
                .flatMap(s -> s.stream())
                .collect(Collectors.toSet());
    }

    void addTestToClasses(TestInfo ti, Collection coverage) {
        for (BlockLocation each : coverage) {
            ClassName clazz = each.getLocation().getClassName();
            Map> linesToTests = lineCoverage.getOrDefault(clazz, new LinkedHashMap<>(0));
            for (int line : getLinesForBlock(each)) {
                addTestToClassLine(each.getLocation().getClassName(), linesToTests, ti, line);
            }
            // can we get blocks from different classes?
            this.lineCoverage.put(each.getLocation().getClassName(), linesToTests);
        }
    }
    private void addTestToClassLine(ClassName clazz,
                                    Map> linesToTests,
                                    TestInfo test,
                                    int line) {
        ClassLine cl = new ClassLine(clazz, line);
        Set tis = linesToTests.getOrDefault(cl, new TreeSet<>(new TestInfoNameComparator()));
        tis.add(test);
        linesToTests.put(cl, tis);
    }


    private Map> getLineCoverageForClassName(final ClassName clazz) {
        return this.lineCoverage.getOrDefault(clazz, Collections.emptyMap());
    }

    private static Function keyFromClassInfo() {
        return c -> keyFromSourceAndPackage(c.rawNode().sourceFile, c.name()
                .getPackage().asJavaName());
    }

    private static String keyFromSourceAndPackage(final String sourceFile,
                                                  final String packageName) {
        return packageName + " " + sourceFile;
    }

    private Set getLinesForBlock(BlockLocation bl) {
        Set lines = this.blocksToLines.get(bl);
        if (lines == null) {
            calculateLinesForBlocks(bl.getLocation().getClassName());
            lines = this.blocksToLines.get(bl);
            if (lines == null) {
                lines = Collections.emptySet();
            }
        }

        return lines;
    }

    private void calculateLinesForBlocks(ClassName className) {
        final Map> lines = this.lm.mapLines(className);
        this.blocksToLines.putAll(lines);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy