From 95e8102725b59780c07e89d4fca9a7563f12c976 Mon Sep 17 00:00:00 2001 From: Henry Coles Date: Thu, 12 Jan 2023 09:29:33 +0000 Subject: [PATCH] New extension points Adds new extension points to allow post analysis modification of coverage and mutation analysis results. Extensions points have multiple potential uses, but first use case is supporting the 'un-inlining' of inlined kotlin functions. Change requires alteration of existing interfaces which may be incompatible with some third party plugins. --- README.md | 5 +- .../aggregate/CodeSourceAggregator.java | 3 +- .../java/org/pitest/classpath/CodeSource.java | 74 +++------------- .../pitest/classpath/CodeSourceFactory.java | 7 ++ .../pitest/classpath/DefaultCodeSource.java | 85 +++++++++++++++++++ .../java/org/pitest/coverage/ClassLines.java | 21 +++++ .../org/pitest/coverage/CoverageData.java | 33 +------ .../org/pitest/coverage/CoverageDatabase.java | 2 - .../pitest/coverage/LegacyClassCoverage.java | 28 +++--- .../java/org/pitest/coverage/NoCoverage.java | 20 ++--- .../org/pitest/coverage/ReportCoverage.java | 8 +- .../CompoundMutationResultInterceptor.java | 35 ++++++++ .../mutationtest/ListenerArguments.java | 10 +-- .../MutationResultInterceptor.java | 32 +++++++ .../build/CoverageTransformer.java | 10 +++ .../build/CoverageTransformerFactory.java | 9 ++ .../mutationtest/config/PluginServices.java | 18 ++++ .../mutationtest/config/SettingsFactory.java | 34 ++++++++ .../execute/MutationAnalysisExecutor.java | 27 ++++-- .../mutationtest/tooling/EntryPoint.java | 8 +- .../tooling/MutationCoverage.java | 34 +++++++- .../tooling/MutationStrategies.java | 20 ++++- ...ceTest.java => DefaultCodeSourceTest.java} | 4 +- .../org/pitest/coverage/ClassLinesTest.java | 31 +++++++ .../org/pitest/coverage/CoverageDataTest.java | 48 +---------- ...CompoundMutationResultInterceptorTest.java | 78 +++++++++++++++++ .../pitest/mutationtest/ReportTestBase.java | 5 +- .../mutationtest/TestMutationTesting.java | 12 +-- .../report/MutationTestResultMother.java | 35 +++++++- .../tooling/MutationCoverageReportTest.java | 2 +- .../interceptors/BuildVerifierVerifier.java | 5 +- .../report/html/AnnotatedLineFactory.java | 24 ++++-- .../html/MutationHtmlReportListener.java | 13 ++- .../report/html/MutationTestSummaryData.java | 25 ++++-- .../html/MutationHtmlReportListenerTest.java | 4 +- .../html/MutationTestSummaryDataTest.java | 35 +++++--- .../pitest/mutationtest/DetectionStatus.java | 1 + .../config/TestPluginArguments.java | 4 - 38 files changed, 586 insertions(+), 263 deletions(-) create mode 100644 pitest-entry/src/main/java/org/pitest/classpath/CodeSourceFactory.java create mode 100644 pitest-entry/src/main/java/org/pitest/classpath/DefaultCodeSource.java create mode 100644 pitest-entry/src/main/java/org/pitest/mutationtest/CompoundMutationResultInterceptor.java create mode 100644 pitest-entry/src/main/java/org/pitest/mutationtest/MutationResultInterceptor.java create mode 100644 pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformer.java create mode 100644 pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformerFactory.java rename pitest-entry/src/test/java/org/pitest/classpath/{CodeSourceTest.java => DefaultCodeSourceTest.java} (96%) create mode 100644 pitest-entry/src/test/java/org/pitest/mutationtest/CompoundMutationResultInterceptorTest.java diff --git a/README.md b/README.md index 0cdabaee8..9e88abab6 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,12 @@ Read all about it at http://pitest.org ## Releases -## 1.10.5 (unreleased) +## 1.11.0 (unreleased) * #1138 Do not mutate redundant fall through to default switch cases +* #1150 New extension points + +Note that #1150 includes breaking interface changes which may require updates to third party plugins. ## 1.10.4 diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/CodeSourceAggregator.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/CodeSourceAggregator.java index 3b790df9a..9bba03c9b 100644 --- a/pitest-aggregator/src/main/java/org/pitest/aggregate/CodeSourceAggregator.java +++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/CodeSourceAggregator.java @@ -12,6 +12,7 @@ import org.pitest.classpath.ClassPath; import org.pitest.classpath.ClassPathRoot; import org.pitest.classpath.CodeSource; +import org.pitest.classpath.DefaultCodeSource; import org.pitest.classpath.DirectoryClassPathRoot; import org.pitest.classpath.PathFilter; import org.pitest.classpath.ProjectClassPaths; @@ -30,7 +31,7 @@ class CodeSourceAggregator { } public CodeSource createCodeSource() { - return new CodeSource(createProjectClassPaths()); + return new DefaultCodeSource(createProjectClassPaths()); } private ProjectClassPaths createProjectClassPaths() { diff --git a/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java b/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java index 6b667f3ba..74d0f0a5c 100644 --- a/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java +++ b/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java @@ -3,8 +3,6 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.pitest.bytecode.analysis.ClassTree; @@ -12,80 +10,28 @@ import org.pitest.classinfo.ClassInfo; import org.pitest.classinfo.ClassInfoSource; import org.pitest.classinfo.ClassName; -import org.pitest.classinfo.NameToClassInfo; -import org.pitest.classinfo.Repository; -import org.pitest.classinfo.TestToClassMapper; -import org.pitest.functional.Streams; /** * Provides access to code and tests on the classpath */ -public class CodeSource implements ClassInfoSource, ClassByteArraySource { +public interface CodeSource extends ClassInfoSource, ClassByteArraySource { - private final ProjectClassPaths classPath; - private final Repository classRepository; + Stream codeTrees(); - public CodeSource(final ProjectClassPaths classPath) { - this(classPath, new Repository(new ClassPathByteArraySource( - classPath.getClassPath()))); - } + Set getCodeUnderTestNames(); - CodeSource(final ProjectClassPaths classPath, - final Repository classRepository) { - this.classPath = classPath; - this.classRepository = classRepository; - } + Stream testTrees(); - public Stream codeTrees() { - return this.classPath.code().stream() - .map(c -> this.getBytes(c.asJavaName())) - .filter(Optional::isPresent) - .map(maybe -> ClassTree.fromBytes(maybe.get())); - } + ClassPath getClassPath(); - public Set getCodeUnderTestNames() { - return this.classPath.code().stream().collect(Collectors.toSet()); - } + Optional findTestee(String className); - public Stream testTrees() { - return this.classPath.test().stream() - .map(c -> this.getBytes(c.asJavaName())) - .filter(Optional::isPresent) - .map(maybe -> ClassTree.fromBytes(maybe.get())) - .filter(t -> !t.isAbstract()); - } - - public ClassPath getClassPath() { - return this.classPath.getClassPath(); - } - - public Optional findTestee(final String className) { - final TestToClassMapper mapper = new TestToClassMapper(this.classRepository); - return mapper.findTestee(className); - } - - public Collection getClassInfo(final Collection classes) { - return classes.stream() - .flatMap(nameToClassInfo()) - .collect(Collectors.toList()); - } - - public Optional fetchClassBytes(final ClassName clazz) { - return this.classRepository.querySource(clazz); - } + Optional fetchClassBytes(ClassName clazz); @Override - public Optional fetchClass(final ClassName clazz) { - return this.classRepository.fetchClass(clazz); - } - - private Function> nameToClassInfo() { - return new NameToClassInfo(this.classRepository) - .andThen(Streams::fromOptional); - } + Optional fetchClass(ClassName clazz); + Collection getClassInfo(Collection classes); @Override - public Optional getBytes(String clazz) { - return fetchClassBytes(ClassName.fromString(clazz)); - } + Optional getBytes(String clazz); } diff --git a/pitest-entry/src/main/java/org/pitest/classpath/CodeSourceFactory.java b/pitest-entry/src/main/java/org/pitest/classpath/CodeSourceFactory.java new file mode 100644 index 000000000..3f3b14eab --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/classpath/CodeSourceFactory.java @@ -0,0 +1,7 @@ +package org.pitest.classpath; + +import org.pitest.plugin.ToolClasspathPlugin; + +public interface CodeSourceFactory extends ToolClasspathPlugin { + CodeSource createCodeSource(ProjectClassPaths classPath); +} diff --git a/pitest-entry/src/main/java/org/pitest/classpath/DefaultCodeSource.java b/pitest-entry/src/main/java/org/pitest/classpath/DefaultCodeSource.java new file mode 100644 index 000000000..b921d8f42 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/classpath/DefaultCodeSource.java @@ -0,0 +1,85 @@ +package org.pitest.classpath; + +import org.pitest.bytecode.analysis.ClassTree; +import org.pitest.classinfo.ClassInfo; +import org.pitest.classinfo.ClassName; +import org.pitest.classinfo.NameToClassInfo; +import org.pitest.classinfo.Repository; +import org.pitest.classinfo.TestToClassMapper; +import org.pitest.functional.Streams; + +import java.util.Collection; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DefaultCodeSource implements CodeSource { + private final ProjectClassPaths classPath; + private final Repository classRepository; + + public DefaultCodeSource(final ProjectClassPaths classPath) { + this(classPath, new Repository(new ClassPathByteArraySource( + classPath.getClassPath()))); + } + + DefaultCodeSource(final ProjectClassPaths classPath, + final Repository classRepository) { + this.classPath = classPath; + this.classRepository = classRepository; + } + + public Stream codeTrees() { + return this.classPath.code().stream() + .map(c -> this.getBytes(c.asJavaName())) + .filter(Optional::isPresent) + .map(maybe -> ClassTree.fromBytes(maybe.get())); + } + + public Set getCodeUnderTestNames() { + return this.classPath.code().stream().collect(Collectors.toSet()); + } + + public Stream testTrees() { + return this.classPath.test().stream() + .map(c -> this.getBytes(c.asJavaName())) + .filter(Optional::isPresent) + .map(maybe -> ClassTree.fromBytes(maybe.get())) + .filter(t -> !t.isAbstract()); + } + + public ClassPath getClassPath() { + return this.classPath.getClassPath(); + } + + public Optional findTestee(final String className) { + final TestToClassMapper mapper = new TestToClassMapper(this.classRepository); + return mapper.findTestee(className); + } + + public Collection getClassInfo(final Collection classes) { + return classes.stream() + .flatMap(nameToClassInfo()) + .collect(Collectors.toList()); + } + + public Optional fetchClassBytes(final ClassName clazz) { + return this.classRepository.querySource(clazz); + } + + @Override + public Optional fetchClass(final ClassName clazz) { + return this.classRepository.fetchClass(clazz); + } + + private Function> nameToClassInfo() { + return new NameToClassInfo(this.classRepository) + .andThen(Streams::fromOptional); + } + + @Override + public Optional getBytes(String clazz) { + return fetchClassBytes(ClassName.fromString(clazz)); + } +} diff --git a/pitest-entry/src/main/java/org/pitest/coverage/ClassLines.java b/pitest-entry/src/main/java/org/pitest/coverage/ClassLines.java index 26b2b40fb..c58593dba 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/ClassLines.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/ClassLines.java @@ -3,8 +3,11 @@ import org.pitest.bytecode.analysis.ClassTree; import org.pitest.classinfo.ClassName; +import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; public final class ClassLines { private final ClassName name; @@ -23,6 +26,16 @@ public ClassName name() { return name; } + public ClassLines relocate(ClassName name) { + return new ClassLines(name, codeLines); + } + + public List asList() { + return codeLines.stream() + .map(l -> new ClassLine(name, l)) + .collect(Collectors.toList()); + } + public int getNumberOfCodeLines() { return this.codeLines.size(); } @@ -47,4 +60,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name); } + + @Override + public String toString() { + return new StringJoiner(", ", ClassLines.class.getSimpleName() + "[", "]") + .add("name=" + name) + .add("codeLines=" + codeLines) + .toString(); + } } diff --git a/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java b/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java index bae386588..5a8982ba4 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java @@ -15,7 +15,6 @@ package org.pitest.coverage; -import org.pitest.bytecode.analysis.ClassTree; import org.pitest.classinfo.ClassInfo; import org.pitest.classinfo.ClassName; import org.pitest.classpath.CodeSource; @@ -78,11 +77,6 @@ public Collection getTestsForBlockLocation(BlockLocation location) { return this.blockCoverage.getOrDefault(location, Collections.emptySet()); } - @Override - public Collection getTestsForClassLine(final ClassLine classLine) { - return legacyClassCoverage.getTestsForClassLine(classLine); - } - public boolean allTestsGreen() { return this.failingTestDescriptions.isEmpty(); } @@ -96,13 +90,13 @@ public List getFailingTestDescriptions() { } @Override - public Optional getCoveredLinesForClass(ClassName clazz) { - return legacyClassCoverage.getCoveredLinesForClass(clazz); + public ClassLines getCodeLinesForClass(ClassName clazz) { + return legacyClassCoverage.getCodeLinesForClass(clazz); } @Override - public int getNumberOfCoveredLines(final Collection mutatedClass) { - return legacyClassCoverage.getNumberOfCoveredLines(mutatedClass); + public Set getCoveredLines(ClassName clazz) { + return legacyClassCoverage.getCoveredLines(clazz); } @Override @@ -144,11 +138,6 @@ public Collection getClassesForFile(final String sourceFile, return legacyClassCoverage.getClassesForFile(sourceFile, packageName); } - @Override - public CoverageSummary createSummary() { - return new CoverageSummary(numberOfLines(), coveredLines()); - } - private BigInteger generateCoverageNumber(Collection coverage) { BigInteger coverageNumber = BigInteger.ZERO; Set testClasses = coverage.stream() @@ -162,20 +151,6 @@ private BigInteger generateCoverageNumber(Collection coverage) { return coverageNumber; } - private Collection allClasses() { - return this.code.getCodeUnderTestNames(); - } - - private int numberOfLines() { - return this.code.codeTrees() - .map(ClassTree::numberOfCodeLines) - .reduce(0, Integer::sum); - } - - private int coveredLines() { - return getNumberOfCoveredLines(allClasses()); - } - private void checkForFailedTest(final CoverageResult cr) { if (!cr.isGreenTest()) { recordTestFailure(cr.getTestUnitDescription()); diff --git a/pitest-entry/src/main/java/org/pitest/coverage/CoverageDatabase.java b/pitest-entry/src/main/java/org/pitest/coverage/CoverageDatabase.java index 0adc6cdde..8ede4e551 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/CoverageDatabase.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/CoverageDatabase.java @@ -13,6 +13,4 @@ public interface CoverageDatabase extends ReportCoverage { BigInteger getCoverageIdForClass(ClassName clazz); - CoverageSummary createSummary(); - } diff --git a/pitest-entry/src/main/java/org/pitest/coverage/LegacyClassCoverage.java b/pitest-entry/src/main/java/org/pitest/coverage/LegacyClassCoverage.java index 749b628d9..646fa01fb 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/LegacyClassCoverage.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/LegacyClassCoverage.java @@ -14,6 +14,7 @@ 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 @@ -41,29 +42,20 @@ public void loadBlockDataOnly(Collection coverageData) { } @Override - public Optional getCoveredLinesForClass(final ClassName clazz) { + public ClassLines getCodeLinesForClass(final ClassName clazz) { return code.fetchClassBytes(clazz) .map(ClassTree::fromBytes) - .map(ClassLines::fromTree); + .map(ClassLines::fromTree) + .orElse(new ClassLines(clazz, Collections.emptySet())); } @Override - public int getNumberOfCoveredLines(Collection mutatedClass) { - return mutatedClass.stream() - .map(this::getLineCoverageForClassName) - .mapToInt(Map::size) - .sum(); - } - - @Override - public Collection getTestsForClassLine(final ClassLine classLine) { - final Collection result = getLineCoverageForClassName( - classLine.getClassName()).get(classLine); - if (result == null) { - return Collections.emptyList(); - } else { - return result; - } + 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 diff --git a/pitest-entry/src/main/java/org/pitest/coverage/NoCoverage.java b/pitest-entry/src/main/java/org/pitest/coverage/NoCoverage.java index b4e56ffe2..7c3de5c6d 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/NoCoverage.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/NoCoverage.java @@ -5,17 +5,17 @@ import java.math.BigInteger; import java.util.Collection; import java.util.Collections; -import java.util.Optional; +import java.util.Set; public class NoCoverage implements CoverageDatabase { @Override - public Optional getCoveredLinesForClass(ClassName clazz) { - return Optional.empty(); + public ClassLines getCodeLinesForClass(ClassName clazz) { + return new ClassLines(clazz, Collections.emptySet()); } @Override - public int getNumberOfCoveredLines(Collection clazz) { - return 0; + public Set getCoveredLines(ClassName clazz) { + return Collections.emptySet(); } @Override @@ -28,11 +28,6 @@ public Collection getTestsForBlockLocation(BlockLocation location) { return Collections.emptyList(); } - @Override - public Collection getTestsForClassLine(ClassLine classLine) { - return Collections.emptyList(); - } - @Override public BigInteger getCoverageIdForClass(ClassName clazz) { return BigInteger.ZERO; @@ -43,9 +38,4 @@ public Collection getClassesForFile(String sourceFile, String packag return Collections.emptyList(); } - @Override - public CoverageSummary createSummary() { - return new CoverageSummary(0,0); - } - } diff --git a/pitest-entry/src/main/java/org/pitest/coverage/ReportCoverage.java b/pitest-entry/src/main/java/org/pitest/coverage/ReportCoverage.java index 3a4c0d843..40a5caf8b 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/ReportCoverage.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/ReportCoverage.java @@ -3,17 +3,15 @@ import org.pitest.classinfo.ClassName; import java.util.Collection; -import java.util.Optional; +import java.util.Set; /** * Subset of coverage interface used by legacy html report */ public interface ReportCoverage { - Optional getCoveredLinesForClass(ClassName clazz); + ClassLines getCodeLinesForClass(ClassName clazz); - int getNumberOfCoveredLines(Collection clazz); - - Collection getTestsForClassLine(ClassLine classLine); + Set getCoveredLines(ClassName clazz); Collection getClassesForFile(String sourceFile, String packageName); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/CompoundMutationResultInterceptor.java b/pitest-entry/src/main/java/org/pitest/mutationtest/CompoundMutationResultInterceptor.java new file mode 100644 index 000000000..a2172880f --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/CompoundMutationResultInterceptor.java @@ -0,0 +1,35 @@ +package org.pitest.mutationtest; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class CompoundMutationResultInterceptor implements MutationResultInterceptor { + + private final List interceptors; + + public CompoundMutationResultInterceptor(List interceptors) { + this.interceptors = interceptors; + } + + @Override + public Collection modify(Collection in) { + Collection result = in; + for (MutationResultInterceptor each : interceptors) { + result = each.modify(result); + } + return result; + } + + @Override + public Collection remaining() { + return interceptors.stream() + .flatMap(i -> i.remaining().stream()) + .collect(Collectors.toList()); + } + + @Override + public String description() { + return "Composite interceptor"; + } +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/ListenerArguments.java b/pitest-entry/src/main/java/org/pitest/mutationtest/ListenerArguments.java index 146974933..dbad394cc 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/ListenerArguments.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/ListenerArguments.java @@ -1,6 +1,6 @@ package org.pitest.mutationtest; -import org.pitest.coverage.CoverageDatabase; +import org.pitest.coverage.ReportCoverage; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.mutationtest.engine.MutationEngine; import org.pitest.plugin.FeatureSetting; @@ -15,7 +15,7 @@ public class ListenerArguments { private final ResultOutputStrategy outputStrategy; - private final CoverageDatabase coverage; + private final ReportCoverage coverage; private final long startTime; private final SourceLocator locator; private final MutationEngine engine; @@ -24,7 +24,7 @@ public class ListenerArguments { private final FeatureSetting setting; public ListenerArguments(ResultOutputStrategy outputStrategy, - CoverageDatabase coverage, + ReportCoverage coverage, SourceLocator locator, MutationEngine engine, long startTime, @@ -34,7 +34,7 @@ public ListenerArguments(ResultOutputStrategy outputStrategy, } ListenerArguments(ResultOutputStrategy outputStrategy, - CoverageDatabase coverage, + ReportCoverage coverage, SourceLocator locator, MutationEngine engine, long startTime, @@ -55,7 +55,7 @@ public ResultOutputStrategy getOutputStrategy() { return this.outputStrategy; } - public CoverageDatabase getCoverage() { + public ReportCoverage getCoverage() { return this.coverage; } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResultInterceptor.java b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResultInterceptor.java new file mode 100644 index 000000000..5896f3b16 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/MutationResultInterceptor.java @@ -0,0 +1,32 @@ +package org.pitest.mutationtest; + +import org.pitest.plugin.ToolClasspathPlugin; + +import java.util.Collection; +import java.util.Collections; + +/** + * Allows modification of results before reporting + */ +public interface MutationResultInterceptor extends ToolClasspathPlugin { + /** + * Modify results for a class + * @param results Results + * @return Results with modifications + */ + Collection modify(Collection results); + + /** + * Called at end of run to provide any results that could not be determined + * until all processing was complete + * @return Collection of results + */ + default Collection remaining() { + return Collections.emptyList(); + } + + @Override + default String description() { + return ""; + } +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformer.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformer.java new file mode 100644 index 000000000..25735e171 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformer.java @@ -0,0 +1,10 @@ +package org.pitest.mutationtest.build; + +import org.pitest.coverage.ReportCoverage; + +/** + * Allows modification of coverage prior to reporting + */ +public interface CoverageTransformer { + ReportCoverage transform(ReportCoverage in); +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformerFactory.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformerFactory.java new file mode 100644 index 000000000..570c1a04a --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/CoverageTransformerFactory.java @@ -0,0 +1,9 @@ +package org.pitest.mutationtest.build; + +import org.pitest.classpath.CodeSource; +import org.pitest.plugin.ToolClasspathPlugin; + +public interface CoverageTransformerFactory extends ToolClasspathPlugin { + + CoverageTransformer create(CodeSource source); +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/config/PluginServices.java b/pitest-entry/src/main/java/org/pitest/mutationtest/config/PluginServices.java index 6fd0f00e4..0d36b894e 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/config/PluginServices.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/config/PluginServices.java @@ -1,6 +1,9 @@ package org.pitest.mutationtest.config; +import org.pitest.classpath.CodeSourceFactory; +import org.pitest.mutationtest.build.CoverageTransformerFactory; import org.pitest.mutationtest.MutationEngineFactory; +import org.pitest.mutationtest.MutationResultInterceptor; import org.pitest.mutationtest.MutationResultListenerFactory; import org.pitest.mutationtest.build.MutationGrouperFactory; import org.pitest.mutationtest.build.MutationInterceptorFactory; @@ -48,7 +51,10 @@ public Collection findToolClasspathPlugins() { l.addAll(findTestPrioritisers()); l.addAll(findInterceptors()); l.addAll(findConfigurationUpdaters()); + l.addAll(findMutationResultInterceptor()); + l.addAll(findCoverageTransformers()); l.addAll(findVerifiers()); + l.addAll(findCodeSources()); return l; } @@ -105,6 +111,18 @@ public List findVerifiers() { return new ArrayList<>(load(BuildVerifierFactory.class)); } + public List findMutationResultInterceptor() { + return new ArrayList<>(load(MutationResultInterceptor.class)); + } + + public List findCoverageTransformers() { + return new ArrayList<>(load(CoverageTransformerFactory.class)); + } + + public List findCodeSources() { + return new ArrayList<>(load(CodeSourceFactory.class)); + } + public Collection findFeatures() { return findToolClasspathPlugins().stream() .filter(p -> p instanceof ProvidesFeature) diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/config/SettingsFactory.java b/pitest-entry/src/main/java/org/pitest/mutationtest/config/SettingsFactory.java index 2f7b01e4d..56915eb72 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/config/SettingsFactory.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/config/SettingsFactory.java @@ -1,11 +1,19 @@ package org.pitest.mutationtest.config; +import org.pitest.classpath.CodeSource; +import org.pitest.classpath.CodeSourceFactory; +import org.pitest.classpath.DefaultCodeSource; +import org.pitest.classpath.ProjectClassPaths; import org.pitest.coverage.CoverageExporter; +import org.pitest.mutationtest.build.CoverageTransformer; +import org.pitest.mutationtest.build.CoverageTransformerFactory; import org.pitest.coverage.execute.CoverageOptions; import org.pitest.coverage.export.DefaultCoverageExporter; import org.pitest.coverage.export.NullCoverageExporter; import org.pitest.functional.FCollection; +import org.pitest.mutationtest.CompoundMutationResultInterceptor; import org.pitest.mutationtest.MutationEngineFactory; +import org.pitest.mutationtest.MutationResultInterceptor; import org.pitest.mutationtest.MutationResultListenerFactory; import org.pitest.mutationtest.build.CompoundInterceptorFactory; import org.pitest.mutationtest.build.DefaultMutationGrouperFactory; @@ -96,6 +104,17 @@ public MutationGrouperFactory getMutationGrouper() { return new DefaultMutationGrouperFactory(); } + public CodeSource createCodeSource(ProjectClassPaths classPath) { + List sources = this.plugins.findCodeSources(); + if (sources.isEmpty()) { + return new DefaultCodeSource(classPath); + } + if (sources.size() > 1) { + throw new RuntimeException("More than CodeSource found on classpath."); + } + return sources.get(0).createCodeSource(classPath); + } + public void describeFeatures(Consumer enabled, Consumer disabled) { final FeatureParser parser = new FeatureParser(); final Collection available = new ArrayList<>(this.plugins.findFeatures()); @@ -158,6 +177,21 @@ public BuildVerifierFactory createVerifier() { return new CompoundBuildVerifierFactory(this.plugins.findVerifiers()); } + public MutationResultInterceptor getResultInterceptor() { + return new CompoundMutationResultInterceptor(this.plugins.findMutationResultInterceptor()); + } + + public CoverageTransformer createCoverageTransformer(CodeSource code) { + List transformers = this.plugins.findCoverageTransformers(); + if (transformers.size() > 1) { + throw new RuntimeException("More than 1 coverage transformer found on classpath"); + } + if (transformers.isEmpty()) { + return cov -> cov; + } + return transformers.get(0).create(code); + } + private Collection findListeners() { final Iterable listeners = this.plugins .findListeners(); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/execute/MutationAnalysisExecutor.java b/pitest-entry/src/main/java/org/pitest/mutationtest/execute/MutationAnalysisExecutor.java index a8da0b492..964cbd96d 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/execute/MutationAnalysisExecutor.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/execute/MutationAnalysisExecutor.java @@ -12,6 +12,7 @@ import org.pitest.mutationtest.ClassMutationResults; import org.pitest.mutationtest.MutationMetaData; +import org.pitest.mutationtest.MutationResultInterceptor; import org.pitest.mutationtest.MutationResultListener; import org.pitest.mutationtest.build.MutationAnalysisUnit; import org.pitest.util.Log; @@ -24,8 +25,11 @@ public class MutationAnalysisExecutor { private final List listeners; private final ThreadPoolExecutor executor; - public MutationAnalysisExecutor(int numberOfThreads, + private final MutationResultInterceptor resultInterceptor; + + public MutationAnalysisExecutor(int numberOfThreads, MutationResultInterceptor interceptor, List listeners) { + this.resultInterceptor = interceptor; this.listeners = listeners; this.executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), @@ -59,15 +63,24 @@ public void run(final List testUnits) { } private void processResult(List> results) - throws InterruptedException, ExecutionException { - for (final Future f : results) { - final MutationMetaData r = f.get(); - for (final MutationResultListener l : this.listeners) { - for (final ClassMutationResults cr : r.toClassResults()) { - l.handleMutationResult(cr); + throws InterruptedException, ExecutionException { + for (Future f : results) { + MutationMetaData metaData = f.get(); + for (ClassMutationResults cr : resultInterceptor.modify(metaData.toClassResults())) { + for (MutationResultListener listener : this.listeners) { + listener.handleMutationResult(cr); } } } + + // handle any results held back from processing. Only known + // use case here is inlined code consolidation. + for (ClassMutationResults each : resultInterceptor.remaining()) { + for (MutationResultListener listener : this.listeners) { + listener.handleMutationResult(each); + } + } + } private void signalRunStartToAllListeners() { diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/EntryPoint.java b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/EntryPoint.java index 7a9e15677..c12766fce 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/EntryPoint.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/EntryPoint.java @@ -106,21 +106,21 @@ public AnalysisResult execute(File baseDir, ReportOptions data, .usingClassPathJar(data.useClasspathJar()); final ProjectClassPaths cps = data.getMutationClassPaths(); - final CodeSource code = new CodeSource(cps); + final CodeSource code = settings.createCodeSource(cps); final Timings timings = new Timings(); final CoverageGenerator coverageDatabase = new DefaultCoverageGenerator( baseDir, coverageOptions, launchOptions, code, settings.createCoverageExporter(), timings, data.getVerbosity()); - final Optional maybeWriter = data.createHistoryWriter(); WriterFactory historyWriter = maybeWriter.orElse(new NullWriterFactory()); final HistoryStore history = makeHistoryStore(data, maybeWriter); final MutationStrategies strategies = new MutationStrategies( - settings.createEngine(), history, coverageDatabase, reportFactory, - reportOutput, settings.createVerifier().create(code)); + settings.createEngine(), history, coverageDatabase, reportFactory, settings.getResultInterceptor(), + settings.createCoverageTransformer(code), + reportOutput, settings.createVerifier().create(code)); final MutationCoverage report = new MutationCoverage(strategies, baseDir, code, data, settings, timings); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java index 14f88d3c5..786984cfe 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationCoverage.java @@ -14,6 +14,7 @@ */ package org.pitest.mutationtest.tooling; +import org.pitest.bytecode.analysis.ClassTree; import org.pitest.classinfo.CachingByteArraySource; import org.pitest.classinfo.ClassByteArraySource; import org.pitest.classinfo.ClassInfo; @@ -26,6 +27,7 @@ import org.pitest.coverage.CoverageGenerator; import org.pitest.coverage.CoverageSummary; import org.pitest.coverage.NoCoverage; +import org.pitest.coverage.ReportCoverage; import org.pitest.coverage.TestInfo; import org.pitest.functional.FCollection; import org.pitest.help.Help; @@ -35,6 +37,7 @@ import org.pitest.mutationtest.ListenerArguments; import org.pitest.mutationtest.MutationAnalyser; import org.pitest.mutationtest.MutationConfig; +import org.pitest.mutationtest.MutationResultInterceptor; import org.pitest.mutationtest.MutationResultListener; import org.pitest.mutationtest.build.MutationAnalysisUnit; import org.pitest.mutationtest.build.MutationGrouper; @@ -172,10 +175,11 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments LOG.fine("Free Memory before analysis start " + (runtime.freeMemory() / MB) + " mb"); - final List config = createConfig(t0, coverageData, history, + ReportCoverage modifiedCoverage = transformCoverage(coverageData); + final List config = createConfig(t0, modifiedCoverage, history, stats, engine); final MutationAnalysisExecutor mae = new MutationAnalysisExecutor( - numberOfThreads(), config); + numberOfThreads(), resultInterceptor(), config); this.timings.registerStart(Timings.Stage.RUN_MUTATION_TESTS); mae.run(tus); this.timings.registerEnd(Timings.Stage.RUN_MUTATION_TESTS); @@ -183,13 +187,31 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments LOG.info("Completed in " + timeSpan(t0)); CombinedStatistics combined = new CombinedStatistics(stats.getStatistics(), - coverageData.createSummary(), issues); + createSummary(modifiedCoverage), issues); printStats(combined); return combined; } + private ReportCoverage transformCoverage(ReportCoverage coverageData) { + // cosmetic changes to coverage are made only after tests are assigned to + // mutants to ensure they cannot affect results. + return strategies.coverageTransformer().transform(coverageData); + } + + private CoverageSummary createSummary(ReportCoverage modifiedCoverage) { + int numberOfCodeLines = this.code.codeTrees() + .map(ClassTree::numberOfCodeLines) + .reduce(0, Integer::sum); + + int coveredLines = this.code.getCodeUnderTestNames().stream() + .mapToInt(c -> modifiedCoverage.getCoveredLines(c).size()) + .sum(); + + return new CoverageSummary(numberOfCodeLines, coveredLines); + } + private Predicate allInterceptors() { return i -> true; } @@ -230,7 +252,7 @@ private int numberOfThreads() { } private List createConfig(long t0, - CoverageDatabase coverageData, + ReportCoverage coverageData, HistoryStore history, MutationStatisticsListener stats, MutationEngine engine) { @@ -254,6 +276,10 @@ private List createConfig(long t0, return ls; } + private MutationResultInterceptor resultInterceptor() { + return this.strategies.resultInterceptor(); + } + private void recordClassPath(HistoryStore history, CoverageDatabase coverageData) { final Set allClassNames = getAllClassesAndTests(coverageData); final Collection ids = FCollection.map( diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationStrategies.java b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationStrategies.java index 77ef6143c..4c2e3d235 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationStrategies.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/tooling/MutationStrategies.java @@ -1,8 +1,10 @@ package org.pitest.mutationtest.tooling; import org.pitest.coverage.CoverageGenerator; +import org.pitest.mutationtest.build.CoverageTransformer; import org.pitest.mutationtest.HistoryStore; import org.pitest.mutationtest.MutationEngineFactory; +import org.pitest.mutationtest.MutationResultInterceptor; import org.pitest.mutationtest.MutationResultListenerFactory; import org.pitest.mutationtest.verify.BuildVerifier; import org.pitest.util.ResultOutputStrategy; @@ -12,6 +14,9 @@ public class MutationStrategies { private final HistoryStore history; private final CoverageGenerator coverage; private final MutationResultListenerFactory listenerFactory; + private final MutationResultInterceptor resultsInterceptor; + + private final CoverageTransformer coverageTransformer; private final BuildVerifier buildVerifier; private final MutationEngineFactory factory; private final ResultOutputStrategy output; @@ -19,10 +24,14 @@ public class MutationStrategies { public MutationStrategies(final MutationEngineFactory factory, final HistoryStore history, final CoverageGenerator coverage, final MutationResultListenerFactory listenerFactory, + final MutationResultInterceptor resultsInterceptor, + final CoverageTransformer coverageTransformer, final ResultOutputStrategy output, final BuildVerifier buildVerifier) { this.history = history; this.coverage = coverage; this.listenerFactory = listenerFactory; + this.resultsInterceptor = resultsInterceptor; + this.coverageTransformer = coverageTransformer; this.buildVerifier = buildVerifier; this.factory = factory; this.output = output; @@ -40,6 +49,10 @@ public MutationResultListenerFactory listenerFactory() { return this.listenerFactory; } + public MutationResultInterceptor resultInterceptor() { + return this.resultsInterceptor; + } + public BuildVerifier buildVerifier() { return this.buildVerifier; } @@ -54,12 +67,15 @@ public ResultOutputStrategy output() { public MutationStrategies with(final MutationEngineFactory factory) { return new MutationStrategies(factory, this.history, this.coverage, - this.listenerFactory, this.output, this.buildVerifier); + this.listenerFactory, this.resultsInterceptor, this.coverageTransformer, this.output, this.buildVerifier); } public MutationStrategies with(final BuildVerifier verifier) { return new MutationStrategies(this.factory, this.history, this.coverage, - this.listenerFactory, this.output, verifier); + this.listenerFactory, this.resultsInterceptor, this.coverageTransformer, this.output, verifier); } + public CoverageTransformer coverageTransformer() { + return this.coverageTransformer; + } } diff --git a/pitest-entry/src/test/java/org/pitest/classpath/CodeSourceTest.java b/pitest-entry/src/test/java/org/pitest/classpath/DefaultCodeSourceTest.java similarity index 96% rename from pitest-entry/src/test/java/org/pitest/classpath/CodeSourceTest.java rename to pitest-entry/src/test/java/org/pitest/classpath/DefaultCodeSourceTest.java index 98bde5ecf..b5a0c678e 100644 --- a/pitest-entry/src/test/java/org/pitest/classpath/CodeSourceTest.java +++ b/pitest-entry/src/test/java/org/pitest/classpath/DefaultCodeSourceTest.java @@ -17,7 +17,7 @@ import org.pitest.classinfo.Repository; import java.util.Optional; -public class CodeSourceTest { +public class DefaultCodeSourceTest { private CodeSource testee; @@ -34,7 +34,7 @@ public class CodeSourceTest { @Before public void setUp() { MockitoAnnotations.openMocks(this); - this.testee = new CodeSource(this.classPath, this.repository); + this.testee = new DefaultCodeSource(this.classPath, this.repository); this.foo = makeClassInfo("Foo"); this.bar = makeClassInfo("Bar"); } diff --git a/pitest-entry/src/test/java/org/pitest/coverage/ClassLinesTest.java b/pitest-entry/src/test/java/org/pitest/coverage/ClassLinesTest.java index a144b8332..4d4164353 100644 --- a/pitest-entry/src/test/java/org/pitest/coverage/ClassLinesTest.java +++ b/pitest-entry/src/test/java/org/pitest/coverage/ClassLinesTest.java @@ -3,6 +3,13 @@ import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.Test; +import org.pitest.classinfo.ClassName; + +import java.util.Collections; +import java.util.HashSet; + +import static org.assertj.core.api.Assertions.assertThat; +import static java.util.Arrays.asList; public class ClassLinesTest { @@ -13,4 +20,28 @@ public void obeysEqualsHashcodeContract() { .withIgnoredFields("codeLines") .verify(); } + + @Test + public void relocateModifiesClassname() { + // note relocate is used within external plugins + ClassName bar = ClassName.fromString("bar"); + ClassLines underTest = new ClassLines(ClassName.fromString("foo"), Collections.emptySet()); + assertThat(underTest.relocate(bar)).isEqualTo(new ClassLines(bar, Collections.emptySet())); + } + + @Test + public void convertsToClassLines() { + ClassName foo = ClassName.fromString("foo"); + ClassLines underTest = new ClassLines(foo, new HashSet<>(asList(1,2))); + + assertThat(underTest.asList()).containsExactly(new ClassLine(foo,1), new ClassLine(foo,2)); + } + + @Test + public void reportsNumberOfCodeLines() { + ClassName foo = ClassName.fromString("foo"); + ClassLines underTest = new ClassLines(foo, new HashSet<>(asList(1,2))); + + assertThat(underTest.getNumberOfCodeLines()).isEqualTo(2); + } } \ No newline at end of file diff --git a/pitest-entry/src/test/java/org/pitest/coverage/CoverageDataTest.java b/pitest-entry/src/test/java/org/pitest/coverage/CoverageDataTest.java index cbe56e80e..f39a703a1 100644 --- a/pitest-entry/src/test/java/org/pitest/coverage/CoverageDataTest.java +++ b/pitest-entry/src/test/java/org/pitest/coverage/CoverageDataTest.java @@ -77,35 +77,12 @@ public void setUp() { public void shouldReturnNoTestsWhenNoTestsCoverALine() { when(this.lm.mapLines(any(ClassName.class))).thenReturn( new HashMap<>()); - final ClassLine line = new ClassLine("foo", 1); - assertEquals(Collections.emptyList(), - this.testee.getTestsForClassLine(line)); - } - - @Test - public void shouldStoreExecutionTimesOfTests() { - - final int line = 1; - final int time = 42; - - final BlockLocationBuilder block = aBlockLocation().withLocation( - aLocation().withClass(this.foo)); - when(this.lm.mapLines(any(ClassName.class))).thenReturn( - makeCoverageMapForBlock(block, line)); - - final CoverageResultBuilder cr = aCoverageResult().withVisitedBlocks( - block.build(1)).withExecutionTime(time); - - this.testee.calculateClassCoverage(cr.build()); - - assertEquals(Arrays.asList(42), FCollection.map( - this.testee.getTestsForClassLine(new ClassLine(this.foo, line)), TestInfo::getTime)); + assertThat(this.testee.getCoveredLines(ClassName.fromString("foo"))).isEmpty(); } @Test public void shouldReportNumberOfCoveredLinesWhenNoneCovered() { - assertEquals(0, this.testee.getNumberOfCoveredLines(Collections - .singletonList(ClassName.fromString("foo")))); + assertThat(this.testee.getCoveredLines(ClassName.fromString("foo"))).isEmpty(); } @Test @@ -121,8 +98,7 @@ public void shouldReportNumberOfCoveredLinesWhenSomeCovered() { this.testee.calculateClassCoverage(cr.build()); - assertEquals(2, this.testee.getNumberOfCoveredLines(Collections - .singletonList(this.foo))); + assertThat(this.testee.getCoveredLines(this.foo)).hasSize(2); } @Test @@ -238,24 +214,6 @@ public void shouldMatchPackageWhenFindingSources() { } - @Test - public void shouldIncludeAllCoveredLinesInCoverageSummary() { - - final BlockLocationBuilder block = aBlockLocation(); - when(this.code.getCodeUnderTestNames()).thenReturn( - Collections.singleton(block.build().getLocation().getClassName())); - when(this.lm.mapLines(any(ClassName.class))).thenReturn( - makeCoverageMapForBlock(block, 1, 2, 3, 4)); - - final CoverageResultBuilder cr = aCoverageResult().withVisitedBlocks( - block.build(1)); - - this.testee.calculateClassCoverage(cr.build()); - - final CoverageSummary actual = this.testee.createSummary(); - assertThat(actual.getNumberOfCoveredLines()).isEqualTo(4); - } - private CoverageResult makeCoverageResult(final String clazz, final String testName, final int time, final int block) { return makeCoverageResult(clazz, new Description(testName), time, block, diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/CompoundMutationResultInterceptorTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/CompoundMutationResultInterceptorTest.java new file mode 100644 index 000000000..a0e19f0ca --- /dev/null +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/CompoundMutationResultInterceptorTest.java @@ -0,0 +1,78 @@ +package org.pitest.mutationtest; + +import org.junit.Test; +import org.pitest.mutationtest.report.MutationTestResultMother; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.pitest.mutationtest.engine.MutationDetailsMother.aMutationDetail; +import static org.pitest.mutationtest.report.MutationTestResultMother.aMutationTestResult; + +public class CompoundMutationResultInterceptorTest { + + @Test + public void chainsChildCallsToModify() { + MutationResultInterceptor a = appendToDesc("foo"); + MutationResultInterceptor b = appendToDesc("bar"); + + CompoundMutationResultInterceptor underTest = new CompoundMutationResultInterceptor(asList(a,b)); + + Collection actual = underTest.modify(someClassResults()); + + assertThat(actual.stream().flatMap(c -> c.getMutations().stream())) + .allMatch(m -> m.getDetails().getDescription().endsWith("foobar")); + } + + @Test + public void combinesRemainingResults() { + MutationResultInterceptor a = hasResult(aMutationTestResult().withMutationDetails(aMutationDetail().withDescription("a"))); + MutationResultInterceptor b = hasResult(aMutationTestResult().withMutationDetails(aMutationDetail().withDescription("b"))); + + CompoundMutationResultInterceptor underTest = new CompoundMutationResultInterceptor(asList(a,b)); + + Collection actual = underTest.remaining(); + + assertThat(actual.stream().flatMap(c -> c.getMutations().stream().map(m -> m.getDetails().getDescription()))) + .containsExactly("a", "b"); + } + + private MutationResultInterceptor hasResult(MutationTestResultMother.MutationTestResultBuilder b) { + return new MutationResultInterceptor() { + @Override + public Collection modify(Collection results) { + return null; + } + + @Override + public Collection remaining() { + return asList(new ClassMutationResults(asList(b.build()))); + } + }; + } + + private static List someClassResults() { + return asList(MutationTestResultMother.createClassResults(aMutationTestResult().build(2))); + } + + private MutationResultInterceptor appendToDesc(final String foo) { + return new MutationResultInterceptor() { + @Override + public Collection modify(Collection results) { + return results.stream() + .map(r -> new ClassMutationResults(r.getMutations().stream().map(m -> appendToDesc(m, foo)).collect(Collectors.toList()))) + .collect(Collectors.toList()); + } + + private MutationResult appendToDesc(MutationResult result, String toAppend) { + return new MutationResult(result.getDetails().withDescription(result.getDetails().getDescription() + toAppend) + , result.getStatusTestPair()); + } + }; + } + +} \ No newline at end of file diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java b/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java index 02863c815..0c7d81c10 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java @@ -14,6 +14,7 @@ import org.junit.Before; import org.pitest.classpath.CodeSource; +import org.pitest.classpath.DefaultCodeSource; import org.pitest.classpath.PathFilter; import org.pitest.classpath.ProjectClassPaths; import org.pitest.coverage.CoverageGenerator; @@ -114,7 +115,7 @@ protected void createAndRun(SettingsFactory settings) { this.data.getClassPath(), this.data.createClassesFilter(), pf); final Timings timings = new Timings(); - final CodeSource code = new CodeSource(cps); + final CodeSource code = new DefaultCodeSource(cps); final CoverageGenerator coverageDatabase = new DefaultCoverageGenerator( null, coverageOptions, launchOptions, code, @@ -124,7 +125,7 @@ protected void createAndRun(SettingsFactory settings) { final MutationStrategies strategies = new MutationStrategies( new GregorEngineFactory(), history, coverageDatabase, - listenerFactory(), null, new NoVerification()); + listenerFactory(), result -> result, cov -> cov, null, new NoVerification()); final MutationCoverage testee = new MutationCoverage(strategies, null, code, this.data, new SettingsFactory(this.data, this.plugins), diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java b/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java index ee3f84188..2dac08967 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java @@ -45,12 +45,11 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.mockito.MockitoAnnotations; import org.pitest.SystemTest; -import org.pitest.classinfo.ClassInfo; import org.pitest.classinfo.ClassName; import org.pitest.classpath.ClassloaderByteArraySource; import org.pitest.classpath.CodeSource; +import org.pitest.classpath.DefaultCodeSource; import org.pitest.classpath.PathFilter; import org.pitest.classpath.ProjectClassPaths; import org.pitest.coverage.CoverageDatabase; @@ -58,7 +57,6 @@ import org.pitest.coverage.execute.CoverageOptions; import org.pitest.coverage.execute.DefaultCoverageGenerator; import org.pitest.coverage.export.NullCoverageExporter; -import org.pitest.functional.FCollection; import org.pitest.functional.prelude.Prelude; import org.pitest.mutationtest.build.CompoundMutationInterceptor; import org.pitest.mutationtest.build.DefaultGrouper; @@ -79,7 +77,6 @@ import org.pitest.process.DefaultJavaExecutableLocator; import org.pitest.process.JavaAgent; import org.pitest.process.LaunchOptions; -import org.pitest.simpletest.SimpleTestPlugin; import org.pitest.simpletest.TestAnnotationForTesting; import org.pitest.util.IsolationUtils; import org.pitest.util.Timings; @@ -98,10 +95,9 @@ public class TestMutationTesting { @Before public void setUp() { - MockitoAnnotations.openMocks(this); - this.config = TestPluginArguments.defaults().withTestPlugin(SimpleTestPlugin.NAME); + this.config = TestPluginArguments.defaults(); this.metaDataExtractor = new MetaDataExtractor(); - this.mae = new MutationAnalysisExecutor(1, + this.mae = new MutationAnalysisExecutor(1, result -> result, Collections . singletonList(this.metaDataExtractor)); } @@ -245,7 +241,7 @@ private void createEngineAndRun(final ReportOptions data, data.createClassesFilter(), pf); final Timings timings = new Timings(); - final CodeSource code = new CodeSource(cps); + final CodeSource code = new DefaultCodeSource(cps); final CoverageGenerator coverageGenerator = new DefaultCoverageGenerator( null, coverageOptions, launchOptions, code, new NullCoverageExporter(), diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java b/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java index 2eb512807..5fc87184c 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/report/MutationTestResultMother.java @@ -15,15 +15,44 @@ package org.pitest.mutationtest.report; import static org.pitest.mutationtest.LocationMother.aMutationId; +import static org.pitest.mutationtest.engine.MutationDetailsMother.aMutationDetail; import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.pitest.coverage.TestInfo; import org.pitest.mutationtest.ClassMutationResults; +import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.MutationStatusTestPair; import org.pitest.mutationtest.engine.MutationDetails; +import org.pitest.mutationtest.engine.MutationDetailsMother; +import org.pitest.quickbuilder.Builder; +import org.pitest.quickbuilder.Generator; +import org.pitest.quickbuilder.SequenceBuilder; +import org.pitest.quickbuilder.builders.QB; public class MutationTestResultMother { + public interface MutationTestResultBuilder extends SequenceBuilder { + MutationTestResultBuilder withMutationDetails(Builder details); + MutationTestResultBuilder withStatusTestPair(MutationStatusTestPair status); + + MutationDetails _MutationDetails(); + MutationStatusTestPair _StatusTestPair(); + } + + public static MutationTestResultBuilder aMutationTestResult() { + return QB.builder(MutationTestResultBuilder.class, seed()) + .withMutationDetails(aMutationDetail()) + .withStatusTestPair(MutationStatusTestPair.notAnalysed(0, DetectionStatus.SURVIVED)); + } + + private static Generator seed() { + return b -> new MutationResult(b._MutationDetails(), b._StatusTestPair()); + } + public static MutationDetails createDetails() { return createDetails("file"); } @@ -34,7 +63,11 @@ public static MutationDetails createDetails(final String sourceFile) { public static ClassMutationResults createClassResults( final MutationResult... mrs) { - return new ClassMutationResults(Arrays.asList(mrs)); + return createClassResults(Arrays.asList(mrs)); + } + + public static ClassMutationResults createClassResults(List mrs) { + return new ClassMutationResults(mrs); } } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/tooling/MutationCoverageReportTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/tooling/MutationCoverageReportTest.java index 184329efe..baa48dd03 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/tooling/MutationCoverageReportTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/tooling/MutationCoverageReportTest.java @@ -215,7 +215,7 @@ private List aMutantIn(Class clazz) { private CombinedStatistics createAndRunTestee() { final MutationStrategies strategies = new MutationStrategies( new GregorEngineFactory(), this.history, this.coverage, - this.listenerFactory, this.output, this.verifier).with(this.mutationFactory); + this.listenerFactory, result -> result, cov -> cov, this.output, this.verifier).with(this.mutationFactory); this.testee = new MutationCoverage(strategies, null, this.code, this.data, new SettingsFactory(this.data, PluginServices.makeForContextLoader()), diff --git a/pitest-entry/src/test/java/org/pitest/verifier/interceptors/BuildVerifierVerifier.java b/pitest-entry/src/test/java/org/pitest/verifier/interceptors/BuildVerifierVerifier.java index 360ad11ec..830184cd5 100644 --- a/pitest-entry/src/test/java/org/pitest/verifier/interceptors/BuildVerifierVerifier.java +++ b/pitest-entry/src/test/java/org/pitest/verifier/interceptors/BuildVerifierVerifier.java @@ -9,6 +9,7 @@ import org.pitest.classpath.ClassPathRoot; import org.pitest.classpath.ClassloaderByteArraySource; import org.pitest.classpath.CodeSource; +import org.pitest.classpath.DefaultCodeSource; import org.pitest.classpath.PathFilter; import org.pitest.classpath.ProjectClassPaths; import org.pitest.mutationtest.config.PluginServices; @@ -88,7 +89,7 @@ public static CodeSource codeSourceReturning(ClassPathRoot root) { final PathFilter pf = new PathFilter(p -> true, p -> true); final ProjectClassPaths pcp = new ProjectClassPaths( new ClassPath(root), new ClassFilter(c -> true, c -> true), pf); - return new CodeSource(pcp); + return new DefaultCodeSource(pcp); } public static ClassTree aValidClass() { @@ -100,7 +101,7 @@ private static CodeSource emptyCodeSource() { final PathFilter pf = new PathFilter(p -> true, p -> true); final ProjectClassPaths pcp = new ProjectClassPaths( new ClassPath(), new ClassFilter(c -> true, c -> true), pf); - return new CodeSource(pcp); + return new DefaultCodeSource(pcp); } } diff --git a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/AnnotatedLineFactory.java b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/AnnotatedLineFactory.java index d9a8e40a7..bcd0fe38b 100644 --- a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/AnnotatedLineFactory.java +++ b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/AnnotatedLineFactory.java @@ -14,7 +14,6 @@ */ package org.pitest.mutationtest.report.html; -import org.pitest.coverage.ClassLine; import org.pitest.coverage.ClassLines; import org.pitest.coverage.ReportCoverage; import org.pitest.functional.FCollection; @@ -25,6 +24,7 @@ import java.io.Reader; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -32,15 +32,24 @@ public class AnnotatedLineFactory { private final Collection mutations; - private final ReportCoverage statistics; + private final ReportCoverage coverage; private final Collection classesInFile; + private final Set coveredLines; + public AnnotatedLineFactory( - final Collection mutations, - final ReportCoverage statistics, final Collection classes) { + final Collection mutations, + final ReportCoverage coverage, final Collection classes) { this.mutations = mutations; - this.statistics = statistics; + this.coverage = coverage; this.classesInFile = classes; + this.coveredLines = findCoveredLines(classes,coverage); + } + + private Set findCoveredLines(Collection classes, ReportCoverage coverage) { + return classes.stream() + .flatMap(cl -> coverage.getCoveredLines(cl.name()).stream().map(l -> l.getLineNumber())) + .collect(Collectors.toSet()); } public List convert(final Reader source) throws IOException { @@ -97,10 +106,7 @@ private boolean isCodeLine(final int line) { } private boolean isLineCovered(final int line) { - final Predicate predicate = a -> !AnnotatedLineFactory.this.statistics.getTestsForClassLine( - new ClassLine(a.name().asInternalName(), line)).isEmpty(); - return FCollection.contains(this.classesInFile, predicate); - + return coveredLines.contains(line); } } diff --git a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationHtmlReportListener.java b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationHtmlReportListener.java index 5fb6d5cce..51654ac42 100644 --- a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationHtmlReportListener.java +++ b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationHtmlReportListener.java @@ -33,7 +33,6 @@ import java.io.Writer; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -43,6 +42,8 @@ import java.util.function.Function; import java.util.logging.Level; +import static java.util.Arrays.asList; + public class MutationHtmlReportListener implements MutationResultListener { private final ResultOutputStrategy outputStrategy; @@ -62,7 +63,7 @@ public MutationHtmlReportListener(Charset outputCharset, final ReportCoverage co this.outputCharset = outputCharset; this.coverage = coverage; this.outputStrategy = outputStrategy; - this.sourceRoots = new HashSet<>(Arrays.asList(locators)); + this.sourceRoots = new HashSet<>(asList(locators)); this.mutatorNames = new HashSet<>(mutatorNames); this.css = loadCss(); } @@ -120,14 +121,10 @@ private PackageSummaryData collectPackageSummaries( public MutationTestSummaryData createSummaryData( final ReportCoverage coverage, final ClassMutationResults data) { - final List lines = this.coverage.getCoveredLinesForClass(data - .getMutatedClass()) - .map(l -> Collections.singletonList(l)) - .orElse(Collections.emptyList()); + final List lines = asList(this.coverage.getCodeLinesForClass(data.getMutatedClass())); return new MutationTestSummaryData(data.getFileName(), data.getMutations(), - this.mutatorNames, lines, coverage.getNumberOfCoveredLines(Collections - .singleton(data.getMutatedClass()))); + this.mutatorNames, lines, coverage.getCoveredLines(data.getMutatedClass()).size()); } private SourceFile createAnnotatedSourceFile( diff --git a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationTestSummaryData.java b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationTestSummaryData.java index a42dd358d..9a12f7a86 100644 --- a/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationTestSummaryData.java +++ b/pitest-html-report/src/main/java/org/pitest/mutationtest/report/html/MutationTestSummaryData.java @@ -14,27 +14,30 @@ */ package org.pitest.mutationtest.report.html; -import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.function.BiFunction; import java.util.function.Function; import java.util.logging.Level; +import java.util.stream.Collectors; import org.pitest.coverage.ClassLines; import org.pitest.coverage.TestInfo; import org.pitest.functional.FCollection; import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.engine.MutationIdentifier; import org.pitest.util.Log; public class MutationTestSummaryData { private final String fileName; private final Set mutators = new TreeSet<>(); - private final Collection mutations = new ArrayList<>(); + private final Map mutations = new HashMap<>(); private final Set classes = new HashSet<>(); private long numberOfCoveredLines; @@ -44,7 +47,7 @@ public MutationTestSummaryData(final String fileName, final Collection mutators, final Collection classes, final long numberOfCoveredLines) { this.fileName = fileName; - this.mutations.addAll(results); + this.mutations.putAll(resultsToMap(results)); this.mutators.addAll(mutators); this.classes.addAll(classes); this.numberOfCoveredLines = numberOfCoveredLines; @@ -62,7 +65,7 @@ public MutationTotals getTotals() { } private long getNumberOfMutationsWithCoverage() { - return this.mutations.stream() + return this.mutations.values().stream() .filter(it -> it.getStatus().hasCoverage()) .count(); } @@ -83,7 +86,8 @@ public String getPackageName() { } public void add(final MutationTestSummaryData data) { - this.mutations.addAll(data.mutations); + // FIXME, would need to replace here instead of add + this.mutations.putAll(data.mutations); this.mutators.addAll(data.getMutators()); final int classesBefore = this.classes.size(); this.classes.addAll(data.classes); @@ -94,7 +98,7 @@ public void add(final MutationTestSummaryData data) { public Collection getTests() { final Set uniqueTests = new HashSet<>(); - FCollection.flatMapTo(this.mutations, mutationToTargettedTests(), + FCollection.flatMapTo(this.mutations.values(), mutationToTargettedTests(), uniqueTests); return uniqueTests; } @@ -112,7 +116,7 @@ public Set getMutators() { } public MutationResultList getResults() { - return new MutationResultList(this.mutations); + return new MutationResultList(this.mutations.values()); } public Collection getClasses() { @@ -133,7 +137,7 @@ private long getNumberOfMutations() { private long getNumberOfMutationsDetected() { int count = 0; - for (final MutationResult each : this.mutations) { + for (final MutationResult each : this.mutations.values()) { if (each.getStatus().isDetected()) { count++; } @@ -145,4 +149,9 @@ private Function> mutationToTargettedTests() return a -> a.getDetails().getTestsInOrder(); } + private static Map resultsToMap(Collection results) { + return results.stream().collect(Collectors.toMap(mr -> mr.getDetails().getId(), Function.identity())); + } + + } diff --git a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationHtmlReportListenerTest.java b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationHtmlReportListenerTest.java index 34f23460c..909538f57 100644 --- a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationHtmlReportListenerTest.java +++ b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationHtmlReportListenerTest.java @@ -65,8 +65,8 @@ public void setUp() { when(this.outputStrategy.createWriterForFile(any(String.class))) .thenReturn(this.writer); - when(this.coverageDb.getCoveredLinesForClass(any(ClassName.class))).thenReturn( - Optional.of(this.classInfo)); + when(this.coverageDb.getCodeLinesForClass(any(ClassName.class))).thenReturn( + this.classInfo); this.testee = new MutationHtmlReportListener(StandardCharsets.UTF_8, this.coverageDb, this.outputStrategy, Collections.emptyList(), this.sourceLocator); diff --git a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationTestSummaryDataTest.java b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationTestSummaryDataTest.java index a4de2b495..1d8ac0bc8 100644 --- a/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationTestSummaryDataTest.java +++ b/pitest-html-report/src/test/java/org/pitest/mutationtest/report/html/MutationTestSummaryDataTest.java @@ -6,6 +6,7 @@ import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationResult; import org.pitest.mutationtest.MutationStatusTestPair; +import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.mutationtest.engine.gregor.MethodMutatorFactory; import org.pitest.mutationtest.engine.gregor.config.Mutator; @@ -18,6 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.pitest.mutationtest.LocationMother.aMutationId; +import static org.pitest.mutationtest.engine.MutationDetailsMother.aMutationDetail; public class MutationTestSummaryDataTest { @@ -100,9 +103,9 @@ public void shouldReturnCorrectNumberOfLinesCoveredWhenCombiningResultsForDiffer @Test public void shouldReturnCorrectTestStrengthWhenAnalysedInOneUnit() { this.testee = buildSummaryDataWithMutationResults(makeClass(), - aMutationResult(DetectionStatus.NO_COVERAGE), - aMutationResult(DetectionStatus.KILLED), - aMutationResult(DetectionStatus.SURVIVED) + aMutationResult(DetectionStatus.NO_COVERAGE, "a"), + aMutationResult(DetectionStatus.KILLED, "b"), + aMutationResult(DetectionStatus.SURVIVED, "c") ); assertEquals(50, this.testee.getTotals().getTestStrength()); } @@ -111,13 +114,13 @@ public void shouldReturnCorrectTestStrengthWhenAnalysedInOneUnit() { public void shouldReturnCorrectTestStrengthWhenAnalysedInTwoUnits() { ClassLines clazz = makeClass(); this.testee = buildSummaryDataWithMutationResults(clazz, - aMutationResult(DetectionStatus.NO_COVERAGE), - aMutationResult(DetectionStatus.KILLED), - aMutationResult(DetectionStatus.SURVIVED) + aMutationResult(DetectionStatus.NO_COVERAGE, "a"), + aMutationResult(DetectionStatus.KILLED, "b"), + aMutationResult(DetectionStatus.SURVIVED, "c") ); final MutationTestSummaryData additionalData = buildSummaryDataWithMutationResults(clazz, - aMutationResult(DetectionStatus.KILLED), - aMutationResult(DetectionStatus.KILLED) + aMutationResult(DetectionStatus.KILLED, "d"), + aMutationResult(DetectionStatus.KILLED, "e") ); this.testee.add(additionalData); assertEquals(75, this.testee.getTotals().getTestStrength()); @@ -126,13 +129,13 @@ public void shouldReturnCorrectTestStrengthWhenAnalysedInTwoUnits() { @Test public void shouldReturnCorrectTestStrengthWhenWhenCombiningResultsForDifferentClasses() { this.testee = buildSummaryDataWithMutationResults(makeClass(100), - aMutationResult(DetectionStatus.NO_COVERAGE), - aMutationResult(DetectionStatus.KILLED), - aMutationResult(DetectionStatus.SURVIVED) + aMutationResult(DetectionStatus.NO_COVERAGE, "a"), + aMutationResult(DetectionStatus.KILLED, "b"), + aMutationResult(DetectionStatus.SURVIVED, "c") ); final MutationTestSummaryData additionalData = buildSummaryDataWithMutationResults(makeClass(200), - aMutationResult(DetectionStatus.KILLED), - aMutationResult(DetectionStatus.KILLED) + aMutationResult(DetectionStatus.KILLED, "d"), + aMutationResult(DetectionStatus.KILLED, "e") ); this.testee.add(additionalData); assertEquals(75, this.testee.getTotals().getTestStrength()); @@ -182,7 +185,11 @@ private MutationTestSummaryData buildSummaryDataWithMutationResults(ClassLines c } private MutationResult aMutationResult(DetectionStatus status) { - return new MutationResult(null, new MutationStatusTestPair(1, status, "A test")); + return new MutationResult(aMutationDetail().build(), new MutationStatusTestPair(1, status, "A test")); + } + + private MutationResult aMutationResult(DetectionStatus status, String mutator) { + return new MutationResult(aMutationDetail().withId(aMutationId().withMutator(mutator)).build(), new MutationStatusTestPair(1, status, "A test")); } private MutationTestSummaryData buildSummaryDataMutators() { diff --git a/pitest/src/main/java/org/pitest/mutationtest/DetectionStatus.java b/pitest/src/main/java/org/pitest/mutationtest/DetectionStatus.java index c75c21367..d5a85dc67 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/DetectionStatus.java +++ b/pitest/src/main/java/org/pitest/mutationtest/DetectionStatus.java @@ -67,6 +67,7 @@ public enum DetectionStatus { */ NO_COVERAGE(false); + private final boolean detected; DetectionStatus(final boolean detected) { diff --git a/pitest/src/main/java/org/pitest/mutationtest/config/TestPluginArguments.java b/pitest/src/main/java/org/pitest/mutationtest/config/TestPluginArguments.java index c281f0215..d3b137238 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/config/TestPluginArguments.java +++ b/pitest/src/main/java/org/pitest/mutationtest/config/TestPluginArguments.java @@ -33,10 +33,6 @@ public static TestPluginArguments defaults() { Collections.emptyList(), false); } - public TestPluginArguments withTestPlugin(String plugin) { - return new TestPluginArguments(this.groupConfig, this.excludedRunners, this.includedTestMethods, this.skipFailingTests); - } - public TestGroupConfig getGroupConfig() { return this.groupConfig; }