diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/AggregationResult.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/AggregationResult.java
new file mode 100644
index 000000000..ae2187552
--- /dev/null
+++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/AggregationResult.java
@@ -0,0 +1,32 @@
+package org.pitest.aggregate;
+
+public class AggregationResult {
+ private final long mutations;
+ private final long mutationsSurvived;
+ private final int mutationCoverage;
+
+ private final int testStrength;
+
+ public AggregationResult(long mutations, long mutationsSurvived, int mutationCoverage, int testStrength) {
+ this.mutations = mutations;
+ this.mutationsSurvived = mutationsSurvived;
+ this.mutationCoverage = mutationCoverage;
+ this.testStrength = testStrength;
+ }
+
+ public long getMutations() {
+ return mutations;
+ }
+
+ public long getMutationsSurvived() {
+ return mutationsSurvived;
+ }
+
+ public int getMutationCoverage() {
+ return mutationCoverage;
+ }
+
+ public int getTestStrength() {
+ return testStrength;
+ }
+}
diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregator.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregator.java
index e3b514ccb..9a0239fa9 100644
--- a/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregator.java
+++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregator.java
@@ -51,17 +51,23 @@ private ReportAggregator(final ResultOutputStrategy resultOutputStrategy, final
this.outputCharset = outputCharset;
}
- public void aggregateReport() throws ReportAggregationException {
+ public AggregationResult aggregateReport() throws ReportAggregationException {
final MutationMetaData mutationMetaData = new MutationMetaData(new ArrayList<>(this.mutationLoader.loadData()));
final MutationResultListener mutationResultListener = createResultListener(mutationMetaData);
+ final ReportAggregatorResultListener reportAggregatorResultListener = new ReportAggregatorResultListener();
+ reportAggregatorResultListener.runStart();
mutationResultListener.runStart();
for (final ClassMutationResults mutationResults : mutationMetaData.toClassResults()) {
+ reportAggregatorResultListener.handleMutationResult(mutationResults);
mutationResultListener.handleMutationResult(mutationResults);
}
+ reportAggregatorResultListener.runEnd();
mutationResultListener.runEnd();
+
+ return reportAggregatorResultListener.result();
}
private MutationResultListener createResultListener(final MutationMetaData mutationMetaData) throws ReportAggregationException {
diff --git a/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregatorResultListener.java b/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregatorResultListener.java
new file mode 100644
index 000000000..8637e652d
--- /dev/null
+++ b/pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregatorResultListener.java
@@ -0,0 +1,32 @@
+package org.pitest.aggregate;
+
+import org.pitest.mutationtest.ClassMutationResults;
+import org.pitest.mutationtest.MutationResultListener;
+import org.pitest.mutationtest.report.html.MutationTotals;
+
+public class ReportAggregatorResultListener implements MutationResultListener {
+ MutationTotals totals = new MutationTotals();
+
+ @Override
+ public void runStart() {
+ // nothing to do here
+ }
+
+ @Override
+ public void handleMutationResult(ClassMutationResults results) {
+ totals.addFiles(1);
+ totals.addMutations(results.getMutations().size());
+ totals.addMutationsDetetcted(results.getMutations().stream().filter(mutation -> mutation.getStatus().isDetected()).count());
+ totals.addMutationsWithCoverage(results.getMutations().stream().filter(it -> it.getStatus().hasCoverage()).count());
+ }
+
+ @Override
+ public void runEnd() {
+ // nothing to do here
+ }
+
+ public AggregationResult result() {
+ return new AggregationResult(totals.getNumberOfMutations(), totals.getNumberOfMutations() - totals.getNumberOfMutationsDetected(),
+ totals.getMutationCoverage(), totals.getTestStrength());
+ }
+}
diff --git a/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java b/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java
index 4ec7d2c12..724447bc6 100755
--- a/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java
+++ b/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java
@@ -253,7 +253,7 @@ public void shouldComputeReportOfTheSubModule()
assertTrue("coverage included",
projectReportsHtmlContents
- .contains("89%"));
+ .contains("85%"));
}
/*
diff --git a/pitest-maven-verification/src/test/resources/pit-sub-module/pom.xml b/pitest-maven-verification/src/test/resources/pit-sub-module/pom.xml
index 270f68520..b4baff1a4 100644
--- a/pitest-maven-verification/src/test/resources/pit-sub-module/pom.xml
+++ b/pitest-maven-verification/src/test/resources/pit-sub-module/pom.xml
@@ -41,6 +41,9 @@
true
+ 26
+ 20
+ 6
diff --git a/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/main/java/org/example2/SystemUnderTest.java b/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/main/java/org/example2/SystemUnderTest.java
index 2c7ddd9ad..afc937966 100644
--- a/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/main/java/org/example2/SystemUnderTest.java
+++ b/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/main/java/org/example2/SystemUnderTest.java
@@ -15,10 +15,16 @@ public SystemUnderTest() {
aNumber = -25;
}
}
+
+ public int getNumber() {
+ return aNumber;
+ }
public String toString() {
return "SystemUnderTest";
}
-
+ public boolean isActive() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/test/java/org/example2/SystemUnderTestTest.java b/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/test/java/org/example2/SystemUnderTestTest.java
new file mode 100644
index 000000000..d3b22fa66
--- /dev/null
+++ b/pitest-maven-verification/src/test/resources/pit-sub-module/sub-module-2/src/test/java/org/example2/SystemUnderTestTest.java
@@ -0,0 +1,19 @@
+package org.example2;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNotNull;
+
+import org.junit.Test;
+
+public class SystemUnderTestTest {
+
+ @Test
+ public void testGetNumber() {
+ SystemUnderTest sut = new SystemUnderTest();
+
+ int result = sut.getNumber();
+ assertTrue(result == -25);
+ }
+
+
+}
\ No newline at end of file
diff --git a/pitest-maven/src/main/java/org/pitest/maven/report/AbstractPitAggregationReportMojo.java b/pitest-maven/src/main/java/org/pitest/maven/report/AbstractPitAggregationReportMojo.java
index bff5b5b36..b3a2c7861 100644
--- a/pitest-maven/src/main/java/org/pitest/maven/report/AbstractPitAggregationReportMojo.java
+++ b/pitest-maven/src/main/java/org/pitest/maven/report/AbstractPitAggregationReportMojo.java
@@ -1,10 +1,12 @@
package org.pitest.maven.report;
import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReportException;
import org.codehaus.plexus.util.FileUtils;
+import org.pitest.aggregate.AggregationResult;
import org.pitest.aggregate.ReportAggregator;
import org.pitest.functional.FCollection;
import org.pitest.maven.DependencyFilter;
@@ -36,6 +38,24 @@ abstract class AbstractPitAggregationReportMojo extends PitReportMojo {
@Parameter(property = "reactorProjects", readonly = true)
List reactorProjects;
+ /**
+ * Mutation score threshold at which to fail build
+ */
+ @Parameter(defaultValue = "0", property = "aggregatedMutationThreshold")
+ private int aggregatedMutationThreshold;
+
+ /**
+ * Test strength score threshold at which to fail build
+ */
+ @Parameter(defaultValue = "0", property = "aggregatedTestStrengthThreshold")
+ private int aggregatedTestStrengthThreshold;
+
+ /**
+ * Maximum surviving mutants to allow
+ */
+ @Parameter(defaultValue = "-1", property = "aggregatedMaxSurviving")
+ private int aggregatedMaxSurviving = -1;
+
private final ReportSourceLocator reportSourceLocator = new ReportSourceLocator();
/**
@@ -69,7 +89,12 @@ protected void executeReport(final Locale locale)
new UndatedReportDirCreationStrategy()))
.build();
- reportAggregator.aggregateReport();
+ AggregationResult result = reportAggregator.aggregateReport();
+
+ throwErrorIfTestStrengthBelowThreshold(result.getTestStrength());
+ throwErrorIfScoreBelowThreshold(result.getMutationCoverage());
+ throwErrorIfMoreThanMaximumSurvivors(result.getMutationsSurvived());
+
} catch (final Exception e) {
throw new MavenReportException(e.getMessage(), e);
}
@@ -138,4 +163,34 @@ private List getCompiledDirs(final MavenProject project)
project.getBuild().getTestOutputDirectory()),
sourceRoots);
}
+
+ private void throwErrorIfScoreBelowThreshold(final int mutationCoverage)
+ throws MojoFailureException {
+ if ((this.aggregatedMutationThreshold != 0)
+ && (mutationCoverage < this.aggregatedMutationThreshold)) {
+ throw new MojoFailureException("Mutation score of "
+ + mutationCoverage + " is below threshold of "
+ + this.aggregatedMutationThreshold);
+ }
+ }
+
+ private void throwErrorIfTestStrengthBelowThreshold(final int testStrength)
+ throws MojoFailureException {
+ if ((this.aggregatedTestStrengthThreshold != 0)
+ && (testStrength < this.aggregatedTestStrengthThreshold)) {
+ throw new MojoFailureException("Test strength score of "
+ + testStrength + " is below threshold of "
+ + this.aggregatedTestStrengthThreshold);
+ }
+ }
+
+ private void throwErrorIfMoreThanMaximumSurvivors(final long mutationsSurvived)
+ throws MojoFailureException {
+ if ((this.aggregatedMaxSurviving >= 0)
+ && (mutationsSurvived > this.aggregatedMaxSurviving)) {
+ throw new MojoFailureException("Had "
+ + mutationsSurvived + " surviving mutants, but only "
+ + this.aggregatedMaxSurviving + " survivors allowed");
+ }
+ }
}