Skip to content

Commit

Permalink
pull out interface for report coverage methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry Coles committed Apr 29, 2021
1 parent a5cbb6b commit e0f4b9e
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 159 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
package org.pitest.aggregate;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Logger;

import org.pitest.classpath.CodeSource;
import org.pitest.coverage.BlockCoverage;
import org.pitest.coverage.BlockLocation;
import org.pitest.coverage.CoverageData;
import org.pitest.coverage.CoverageDatabase;
import org.pitest.coverage.InstructionLocation;
import org.pitest.coverage.ReportCoverage;
import org.pitest.coverage.TestInfo;
import org.pitest.coverage.analysis.LineMapper;
import org.pitest.functional.FCollection;
Expand All @@ -31,6 +18,20 @@
import org.pitest.util.Log;
import org.pitest.util.ResultOutputStrategy;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public final class ReportAggregator {
private final ResultOutputStrategy resultOutputStrategy;
private final DataLoader<BlockCoverage> blockCoverageLoader;
Expand Down Expand Up @@ -65,7 +66,7 @@ private MutationResultListener createResultListener(final MutationMetaData mutat
final SourceLocator sourceLocator = new SmartSourceLocator(this.sourceCodeDirectories);

final CodeSource codeSource = this.codeSourceAggregator.createCodeSource();
final CoverageDatabase coverageDatabase = calculateCoverage(codeSource, mutationMetaData);
final ReportCoverage coverageDatabase = calculateCoverage(codeSource);
final Collection<String> mutatorNames = new HashSet<>(FCollection.flatMap(mutationMetaData.getMutations(), resultToMutatorName()));

return new MutationHtmlReportListener(coverageDatabase, this.resultOutputStrategy, mutatorNames, sourceLocator);
Expand All @@ -82,27 +83,34 @@ private static Function<MutationResult, List<String>> resultToMutatorName() {
};
}

private CoverageData calculateCoverage(final CodeSource codeSource, final MutationMetaData metadata) throws ReportAggregationException {
final Collection<BlockCoverage> coverageData = this.blockCoverageLoader.loadData();
private ReportCoverage calculateCoverage(final CodeSource codeSource) throws ReportAggregationException {
try {
final Map<InstructionLocation, Set<TestInfo>> blockCoverageMap = blocksToMap(coverageData);
return new CoverageData(codeSource, new LineMapper(codeSource),blockCoverageMap);
Collection<BlockLocation> coverageData = this.blockCoverageLoader.loadData().stream()
.map(BlockCoverage::getBlock)
.collect(Collectors.toList());
CoverageData cd = new CoverageData(codeSource, new LineMapper(codeSource));
cd.loadBlockDataOnly(coverageData);
return cd;
} catch (final Exception e) {
throw new ReportAggregationException(e.getMessage(), e);
}
}

private Map<InstructionLocation, Set<TestInfo>> blocksToMap(
private Map<TestInfo, Collection<BlockLocation>> blocksToMap(
final Collection<BlockCoverage> coverageData) {
final Map<InstructionLocation, Set<TestInfo>> blockCoverageMap = new HashMap<>();

Map<TestInfo, Collection<BlockLocation>> blockCoverageMap = new HashMap<>();

for (final BlockCoverage blockData : coverageData) {
for (int i = blockData.getBlock().getFirstInsnInBlock();
i <= blockData.getBlock().getLastInsnInBlock(); i++) {
blockCoverageMap.put(new InstructionLocation(blockData.getBlock(), i),
new HashSet<>(
FCollection.map(blockData.getTests(), toTestInfo(blockData))));
List<TestInfo> tests = blockData.getTests().stream()
.map(toTestInfo(blockData))
.collect(Collectors.toList());

for (TestInfo each : tests) {
Collection<BlockLocation> collection = blockCoverageMap.computeIfAbsent(each, k -> new ArrayList<>());
collection.add(blockData.getBlock());
}

}
return blockCoverageMap;
}
Expand Down
110 changes: 14 additions & 96 deletions pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,21 @@

public class CoverageData implements CoverageDatabase {

private static final Logger LOG = Log
.getLogger();
private static final Logger LOG = Log.getLogger();

// We calculate block coverage, but everything currently runs on line
// coverage. Ugly mess of maps below should go when
// api changed to work via blocks
private final Map<InstructionLocation, Set<TestInfo>> instructionCoverage;
private final Map<ClassName, Map<ClassLine, Set<TestInfo>>> lineCoverage = new LinkedHashMap<>();
private final Map<InstructionLocation, Set<TestInfo>> instructionCoverage = new LinkedHashMap<>();
private final LegacyClassCoverage legacyClassCoverage;

private final Map<BlockLocation, Set<Integer>> blocksToLines = new LinkedHashMap<>();
private final CodeSource code;

private final Map<String, Collection<ClassInfo>> classesForFile;

private final CodeSource code;

private final LineMap lm;

private final List<Description> failingTestDescriptions = new ArrayList<>();
private final List<Description> failingTestDescriptions = new ArrayList<>();

public CoverageData(final CodeSource code, final LineMap lm) {
this(code, lm, new LinkedHashMap<>());
}


public CoverageData(final CodeSource code, final LineMap lm, Map<InstructionLocation, Set<TestInfo>> instructionCoverage) {
this.instructionCoverage = instructionCoverage;
this.code = code;
this.lm = lm;
this.classesForFile = FCollection.bucket(this.code.getCode(),
keyFromClassInfo());
this.legacyClassCoverage = new LegacyClassCoverage(code, lm);
}

public void calculateClassCoverage(final CoverageResult cr) {
Expand All @@ -78,7 +63,7 @@ public void calculateClassCoverage(final CoverageResult cr) {
final TestInfo ti = this.createTestInfo(cr.getTestUnitDescription(),
cr.getExecutionTime(), cr.getNumberOfCoveredBlocks());

addTestToClasses(ti,cr.getCoverage());
legacyClassCoverage.addTestToClasses(ti,cr.getCoverage());

for (final BlockLocation each : cr.getCoverage()) {
for (int i = each.getFirstInsnInBlock();
Expand All @@ -88,26 +73,10 @@ public void calculateClassCoverage(final CoverageResult cr) {
}
}

private void addTestToClasses(TestInfo ti, Collection<BlockLocation> coverage) {
for (BlockLocation each : coverage) {
ClassName clazz = each.getLocation().getClassName();
Map<ClassLine, Set<TestInfo>> 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<ClassLine, Set<TestInfo>> linesToTests,
TestInfo test,
int line) {
ClassLine cl = new ClassLine(clazz, line);
Set<TestInfo> tis = linesToTests.getOrDefault(cl, new TreeSet<>(new TestInfoNameComparator()));
tis.add(test);
linesToTests.put(cl, tis);
// populates class with class level data only, without block level data
public void loadBlockDataOnly(Collection<BlockLocation> coverageData) {
legacyClassCoverage.loadBlockDataOnly(coverageData);
}


Expand All @@ -118,13 +87,7 @@ public Collection<TestInfo> getTestsForInstructionLocation(InstructionLocation l

@Override
public Collection<TestInfo> getTestsForClassLine(final ClassLine classLine) {
final Collection<TestInfo> result = getLineCoverageForClassName(
classLine.getClassName()).get(classLine);
if (result == null) {
return Collections.emptyList();
} else {
return result;
}
return legacyClassCoverage.getTestsForClassLine(classLine);
}

public boolean allTestsGreen() {
Expand All @@ -146,17 +109,12 @@ public Collection<ClassInfo> getClassInfo(final Collection<ClassName> classes) {

@Override
public int getNumberOfCoveredLines(final Collection<ClassName> mutatedClass) {
return mutatedClass.stream()
.map(this::getLineCoverageForClassName)
.mapToInt(Map::size)
.sum();
return legacyClassCoverage.getNumberOfCoveredLines(mutatedClass);
}

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

private void addTestsToBlockMap(final TestInfo ti, InstructionLocation each) {
Expand Down Expand Up @@ -190,13 +148,7 @@ private static Function<Entry<InstructionLocation, Set<TestInfo>>, BlockCoverage
@Override
public Collection<ClassInfo> getClassesForFile(final String sourceFile,
String packageName) {
final Collection<ClassInfo> value = classesForFile.get(
keyFromSourceAndPackage(sourceFile, packageName));
if (value == null) {
return Collections.emptyList();
} else {
return value;
}
return legacyClassCoverage.getClassesForFile(sourceFile, packageName);
}

@Override
Expand All @@ -217,18 +169,6 @@ private BigInteger generateCoverageNumber(Collection<TestInfo> coverage) {
return coverageNumber;
}

private static Function<ClassInfo, String> keyFromClassInfo() {

return c -> keyFromSourceAndPackage(c.getSourceFileName(), c.getName()
.getPackage().asJavaName());
}

private static String keyFromSourceAndPackage(final String sourceFile,
final String packageName) {

return packageName + " " + sourceFile;
}

private Collection<ClassName> allClasses() {
return this.code.getCodeUnderTestNames();
}
Expand Down Expand Up @@ -262,28 +202,6 @@ private TestInfo createTestInfo(final Description description,
description.getQualifiedName(), executionTime, testee, linesCovered);
}

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

private Set<Integer> getLinesForBlock(BlockLocation bl) {
Set<Integer> 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<BlockLocation, Set<Integer>> lines = this.lm.mapLines(className);
this.blocksToLines.putAll(lines);
}

private void recordTestFailure(final Description testDescription) {
this.failingTestDescriptions.add(testDescription);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
package org.pitest.coverage;

import org.pitest.classinfo.ClassInfo;
import org.pitest.classinfo.ClassName;

import java.math.BigInteger;
import java.util.Collection;

public interface CoverageDatabase {

Collection<ClassInfo> getClassInfo(Collection<ClassName> classes);

int getNumberOfCoveredLines(Collection<ClassName> clazz);
public interface CoverageDatabase extends ReportCoverage {

Collection<TestInfo> getTestsForClass(ClassName clazz);

Collection<TestInfo> getTestsForInstructionLocation(InstructionLocation location);

Collection<TestInfo> getTestsForClassLine(ClassLine classLine);

BigInteger getCoverageIdForClass(ClassName clazz);

Collection<ClassInfo> getClassesForFile(String sourceFile, String packageName);

CoverageSummary createSummary();

}
Loading

0 comments on commit e0f4b9e

Please sign in to comment.