diff --git a/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java b/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java index 619f99d86..6f9521842 100644 --- a/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java +++ b/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java @@ -268,16 +268,19 @@ public void setArgLine(String value) { this.setOption(ConfigOption.ARG_LINE, value); } + public void setUseClasspathJar(String value) { + this.setOption(ConfigOption.USE_CLASSPATH_JAR, value); + } + + public void setDryRun(String value) { + this.setOption(ConfigOption.DRY_RUN, value); + } + private void setOption(final ConfigOption option, final String value) { if (!"".equals(value)) { this.options.put(option.getParamName(), value); } } - public void setUseClasspathJar(String value) { - this.setOption(ConfigOption.USE_CLASSPATH_JAR, value); - } - - } \ No newline at end of file diff --git a/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java b/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java index 53d110b29..07b73277a 100644 --- a/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java +++ b/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java @@ -503,6 +503,19 @@ public void passesArgLineToJavaTask() { verify(this.arg).setValue("--argLine=-Dfoo=\"bar\""); } + @Test + public void passesDryRunFlagToJavaTask() { + this.pitestTask.setDryRun("true"); + this.pitestTask.execute(this.java); + verify(this.arg).setValue("--dryRun=true"); + } + + @Test + public void defaultDryRunToFalse() { + this.pitestTask.execute(this.java); + verify(this.arg, never()).setValue("--dryRun=true"); + } + private static class PathMatcher implements ArgumentMatcher { private final String[] expectedPaths; diff --git a/pitest-command-line/src/main/java/org/pitest/mutationtest/commandline/OptionsParser.java b/pitest-command-line/src/main/java/org/pitest/mutationtest/commandline/OptionsParser.java index 5719e1f7f..8e8bec934 100644 --- a/pitest-command-line/src/main/java/org/pitest/mutationtest/commandline/OptionsParser.java +++ b/pitest-command-line/src/main/java/org/pitest/mutationtest/commandline/OptionsParser.java @@ -24,6 +24,7 @@ import org.pitest.classpath.ClassPath; import org.pitest.functional.FCollection; import org.pitest.mutationtest.config.ConfigOption; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.testapi.TestGroupConfig; import org.pitest.util.Glob; @@ -54,6 +55,7 @@ import static org.pitest.mutationtest.config.ConfigOption.CLASSPATH_FILE; import static org.pitest.mutationtest.config.ConfigOption.CODE_PATHS; import static org.pitest.mutationtest.config.ConfigOption.COVERAGE_THRESHOLD; +import static org.pitest.mutationtest.config.ConfigOption.DRY_RUN; import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_CLASSES; import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_GROUPS; import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_METHOD; @@ -152,6 +154,7 @@ public class OptionsParser { private final OptionSpec projectBaseSpec; private final OptionSpec inputEncoding; private final OptionSpec outputEncoding; + private final ArgumentAcceptingOptionSpec dryRunSpec; public OptionsParser(Predicate dependencyFilter) { @@ -407,6 +410,12 @@ public OptionsParser(Predicate dependencyFilter) { this.projectBaseSpec = parserAccepts(PROJECT_BASE) .withRequiredArg().ofType(File.class); + this.dryRunSpec = parserAccepts(DRY_RUN) + .withOptionalArg() + .ofType(Boolean.class) + .defaultsTo(VERBOSE.getDefault(Boolean.class)) + .describedAs("enable or disable dry run mode"); + } private OptionSpecBuilder parserAccepts(final ConfigOption option) { @@ -448,21 +457,16 @@ private ParseResult parseCommandLine(final ReportOptions data, data.setArgLine(this.argLine.value(userArgs)); data.addChildJVMArgs(this.jvmArgsProcessor.values(userArgs)); - data.setFullMutationMatrix( - (userArgs.has(this.fullMutationMatrixSpec) && !userArgs.hasArgument(this.fullMutationMatrixSpec)) - || this.fullMutationMatrixSpec.value(userArgs)); - data.setDetectInlinedCode( - (userArgs.has(this.detectInlinedCode) && !userArgs.hasArgument(this.detectInlinedCode)) - || this.detectInlinedCode.value(userArgs)); - data.setIncludeLaunchClasspath( - (userArgs.has(this.includeLaunchClasspathSpec) && !userArgs.hasArgument(this.includeLaunchClasspathSpec)) - || this.includeLaunchClasspathSpec.value(userArgs)); - data.setUseClasspathJar( - (userArgs.has(this.useClasspathJarSpec) && !userArgs.hasArgument(this.useClasspathJarSpec)) - || this.useClasspathJarSpec.value(userArgs)); - data.setShouldCreateTimestampedReports( - (userArgs.has(this.timestampedReportsSpec) && !userArgs.hasArgument(this.timestampedReportsSpec)) - || this.timestampedReportsSpec.value(userArgs)); + data.setFullMutationMatrix(booleanValue(fullMutationMatrixSpec, userArgs)); + + data.setDetectInlinedCode(booleanValue(detectInlinedCode, userArgs)); + + data.setIncludeLaunchClasspath(booleanValue(includeLaunchClasspathSpec, userArgs)); + + data.setUseClasspathJar(booleanValue(useClasspathJarSpec, userArgs)); + + data.setShouldCreateTimestampedReports(booleanValue(timestampedReportsSpec, userArgs)); + data.setNumberOfThreads(this.threadsSpec.value(userArgs)); data.setTimeoutFactor(this.timeoutFactorSpec.value(userArgs)); data.setTimeoutConstant(this.timeoutConstSpec.value(userArgs)); @@ -475,12 +479,10 @@ private ParseResult parseCommandLine(final ReportOptions data, configureVerbosity(data, userArgs); data.addOutputFormats(this.outputFormatSpec.values(userArgs)); - data.setFailWhenNoMutations( - (userArgs.has(this.failWhenNoMutations) && !userArgs.hasArgument(this.failWhenNoMutations)) - || this.failWhenNoMutations.value(userArgs)); - data.setSkipFailingTests( - (userArgs.has(this.skipFailingTests) && !userArgs.hasArgument(this.skipFailingTests)) - || this.skipFailingTests.value(userArgs)); + data.setFailWhenNoMutations(booleanValue(failWhenNoMutations, userArgs)); + + data.setSkipFailingTests(booleanValue(skipFailingTests, userArgs)); + data.setCodePaths(this.codePaths.values(userArgs)); data.setMutationUnitSize(this.mutationUnitSizeSpec.value(userArgs)); data.setHistoryInputLocation(this.historyInputSpec.value(userArgs)); @@ -491,9 +493,7 @@ private ParseResult parseCommandLine(final ReportOptions data, data.setCoverageThreshold(this.coverageThreshHoldSpec.value(userArgs)); data.setMutationEngine(this.mutationEngine.value(userArgs)); data.setFreeFormProperties(listToProperties(this.pluginPropertiesSpec.values(userArgs))); - data.setExportLineCoverage( - (userArgs.has(this.exportLineCoverageSpec) && !userArgs.hasArgument(this.exportLineCoverageSpec)) - || this.exportLineCoverageSpec.value(userArgs)); + data.setExportLineCoverage(booleanValue(exportLineCoverageSpec, userArgs)); setClassPath(userArgs, data); @@ -506,6 +506,8 @@ private ParseResult parseCommandLine(final ReportOptions data, setEncoding(data, userArgs); + configureExecutionMode(data, userArgs); + if (userArgs.has(projectBaseSpec)) { data.setProjectBase(this.projectBaseSpec.value(userArgs).toPath()); } @@ -523,9 +525,7 @@ private void setEncoding(ReportOptions data, OptionSet userArgs) { } private void configureVerbosity(ReportOptions data, OptionSet userArgs) { - boolean isVerbose = (userArgs.has(this.verboseSpec) && !userArgs.hasArgument(this.verboseSpec)) - || this.verboseSpec.value(userArgs); - if (isVerbose) { + if (booleanValue(verboseSpec, userArgs)) { data.setVerbosity(Verbosity.VERBOSE); } else { data.setVerbosity(Verbosity.fromString(this.verbositySpec.value(userArgs))); @@ -533,6 +533,13 @@ private void configureVerbosity(ReportOptions data, OptionSet userArgs) { } + private void configureExecutionMode(ReportOptions data, OptionSet userArgs) { + if (booleanValue(dryRunSpec, userArgs)) { + data.setExecutionMode(ExecutionMode.DRY_RUN); + } + } + + private void setClassPath(final OptionSet userArgs, final ReportOptions data) { final List elements = new ArrayList<>(); @@ -588,5 +595,9 @@ public void printHelp() { } } + private boolean booleanValue(ArgumentAcceptingOptionSpec spec, OptionSet userArgs) { + return (userArgs.has(spec) && !userArgs.hasArgument(spec)) + || spec.value(userArgs); + } } diff --git a/pitest-command-line/src/test/java/org/pitest/mutationtest/commandline/OptionsParserTest.java b/pitest-command-line/src/test/java/org/pitest/mutationtest/commandline/OptionsParserTest.java index 4c13f1b58..2bdc9295b 100644 --- a/pitest-command-line/src/test/java/org/pitest/mutationtest/commandline/OptionsParserTest.java +++ b/pitest-command-line/src/test/java/org/pitest/mutationtest/commandline/OptionsParserTest.java @@ -40,6 +40,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.pitest.mutationtest.config.ConfigOption; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.config.PluginServices; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.mutationtest.engine.gregor.GregorMutationEngine; @@ -703,6 +704,34 @@ public void parsesOutputEncoding() { assertThat(actual.getOutputEncoding()).isEqualTo(StandardCharsets.US_ASCII); } + @Test + public void defaultsToNormalExecution() { + final ReportOptions actual = parseAddingRequiredArgs(""); + assertThat(actual.mode()).isEqualTo(ExecutionMode.NORMAL); + } + + @Test + public void parsesShortFormDryRun() { + final ReportOptions actual = parseAddingRequiredArgs( + "--dryRun"); + assertThat(actual.mode()).isEqualTo(ExecutionMode.DRY_RUN); + } + + @Test + public void parsesLongFormDryRunFalse() { + ReportOptions actual = parseAddingRequiredArgs( + "--dryRun=false"); + assertThat(actual.mode()).isEqualTo(ExecutionMode.NORMAL); + } + + @Test + public void parsesLongFormDryRunTrue() { + ReportOptions actual = parseAddingRequiredArgs( + "--dryRun=true"); + assertThat(actual.mode()).isEqualTo(ExecutionMode.DRY_RUN); + } + + private String getNonCanonicalGregorEngineClassPath() { final String gregorEngineClassPath = GregorMutationEngine.class .getProtectionDomain().getCodeSource().getLocation().getFile(); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/History.java b/pitest-entry/src/main/java/org/pitest/mutationtest/History.java index 7b52dc89a..4eda97934 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/History.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/History.java @@ -10,9 +10,16 @@ public interface History { void initialize(); + + default Predicate limitTests(List mutants) { + return limitTests(); + } + + @Deprecated default Predicate limitTests() { return c -> true; } + void processCoverage(CoverageDatabase coverageData); List analyse(List mutationsForClasses); diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/DryRunUnit.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/DryRunUnit.java new file mode 100644 index 000000000..19c8cf6f2 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/DryRunUnit.java @@ -0,0 +1,50 @@ +package org.pitest.mutationtest.build; + +import org.pitest.mutationtest.DetectionStatus; +import org.pitest.mutationtest.MutationMetaData; +import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.MutationStatusTestPair; +import org.pitest.mutationtest.engine.MutationDetails; +import org.pitest.util.Log; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +public class DryRunUnit implements MutationAnalysisUnit { + private static final Logger LOG = Log.getLogger(); + + private final Collection mutations; + + public DryRunUnit(final Collection mutations) { + this.mutations = mutations; + } + + @Override + public MutationMetaData call() throws Exception { + LOG.fine("Not analysing " + this.mutations.size() + + " mutations as in dry run"); + List results = mutations.stream() + .map(m -> new MutationResult(m, noAnalysis())) + .collect(Collectors.toList()); + return new MutationMetaData(results); + + } + + private MutationStatusTestPair noAnalysis() { + return MutationStatusTestPair.notAnalysed(0, DetectionStatus.NOT_STARTED, Collections.emptyList()); + } + + @Override + public int priority() { + return Integer.MAX_VALUE; + } + + @Override + public Collection mutants() { + return mutations; + } + +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/KnownStatusMutationTestUnit.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/KnownStatusMutationTestUnit.java index 6fb624ca7..e66c652af 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/build/KnownStatusMutationTestUnit.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/KnownStatusMutationTestUnit.java @@ -1,10 +1,13 @@ package org.pitest.mutationtest.build; +import java.util.Collection; import java.util.List; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.pitest.mutationtest.MutationMetaData; import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.util.Log; public class KnownStatusMutationTestUnit implements MutationAnalysisUnit { @@ -30,4 +33,11 @@ public int priority() { return Integer.MAX_VALUE; } + @Override + public Collection mutants() { + return mutations.stream() + .map(MutationResult::getDetails) + .collect(Collectors.toList()); + } + } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationAnalysisUnit.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationAnalysisUnit.java index 84ce45e9f..aaad6aeea 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationAnalysisUnit.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationAnalysisUnit.java @@ -1,8 +1,10 @@ package org.pitest.mutationtest.build; +import java.util.Collection; import java.util.concurrent.Callable; import org.pitest.mutationtest.MutationMetaData; +import org.pitest.mutationtest.engine.MutationDetails; /** * A unit of mutation analysis @@ -11,4 +13,5 @@ public interface MutationAnalysisUnit extends Callable { int priority(); + Collection mutants(); } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestBuilder.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestBuilder.java index 7ec3e9427..f80730e2d 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestBuilder.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestBuilder.java @@ -18,6 +18,7 @@ import org.pitest.mutationtest.History; import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationResult; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.mutationtest.engine.MutationIdentifier; @@ -31,16 +32,19 @@ public class MutationTestBuilder { + private final ExecutionMode mode; private final MutationSource mutationSource; private final History analyser; private final WorkerFactory workerFactory; private final MutationGrouper grouper; - public MutationTestBuilder(final WorkerFactory workerFactory, - final History analyser, - final MutationSource mutationSource, - final MutationGrouper grouper) { + public MutationTestBuilder(ExecutionMode mode, + WorkerFactory workerFactory, + History analyser, + MutationSource mutationSource, + MutationGrouper grouper) { + this.mode = mode; this.mutationSource = mutationSource; this.analyser = analyser; this.workerFactory = workerFactory; @@ -109,7 +113,10 @@ private MutationAnalysisUnit makePreAnalysedUnit( } private MutationAnalysisUnit makeUnanalysedUnit( - final Collection needAnalysis) { + Collection needAnalysis) { + if (mode == ExecutionMode.DRY_RUN) { + return new DryRunUnit(needAnalysis); + } return new MutationTestUnit(needAnalysis, this.workerFactory); } diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestUnit.java b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestUnit.java index 086793cab..824199143 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestUnit.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/build/MutationTestUnit.java @@ -62,6 +62,11 @@ public int priority() { return this.availableMutations.size(); } + @Override + public Collection mutants() { + return availableMutations; + } + private void runTestsInSeperateProcess(final MutationStatusMap mutations) throws IOException, InterruptedException { while (mutations.hasUnrunMutations()) { diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/config/ConfigOption.java b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ConfigOption.java index 682762c90..8ec79ae7e 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/config/ConfigOption.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ConfigOption.java @@ -254,7 +254,12 @@ public enum ConfigOption { /** * Source file encoding */ - OUTPUT_ENCODING("outputEncoding", Charset.defaultCharset().name()); + OUTPUT_ENCODING("outputEncoding", Charset.defaultCharset().name()), + + /** + * Flag to indicate if dry run mode should be enabled + */ + DRY_RUN("dryRun", false); private final String text; private final Serializable defaultValue; diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/config/ExecutionMode.java b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ExecutionMode.java new file mode 100644 index 000000000..f2379c7e8 --- /dev/null +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ExecutionMode.java @@ -0,0 +1,5 @@ +package org.pitest.mutationtest.config; + +public enum ExecutionMode { + NORMAL, DRY_RUN +} diff --git a/pitest-entry/src/main/java/org/pitest/mutationtest/config/ReportOptions.java b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ReportOptions.java index 843fb8b9d..a4ec7f451 100644 --- a/pitest-entry/src/main/java/org/pitest/mutationtest/config/ReportOptions.java +++ b/pitest-entry/src/main/java/org/pitest/mutationtest/config/ReportOptions.java @@ -153,6 +153,8 @@ public class ReportOptions { private boolean arcmutateMissing = true; + private ExecutionMode mode = ExecutionMode.NORMAL; + // currently used only via maven private Map environmentVariables = new HashMap<>(); @@ -675,9 +677,18 @@ public void setArcmutateMissing(boolean arcmutateMissing) { this.arcmutateMissing = arcmutateMissing; } + public ExecutionMode mode() { + return mode; + } + + public void setExecutionMode(ExecutionMode mode) { + this.mode = mode; + } + @Override public String toString() { return new StringJoiner(", ", ReportOptions.class.getSimpleName() + "[", "]") + .add("mode=" + mode) .add("targetClasses=" + targetClasses) .add("excludedMethods=" + excludedMethods) .add("excludedClasses=" + excludedClasses) 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 c776404a5..3533b4375 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 @@ -43,6 +43,7 @@ import org.pitest.mutationtest.build.WorkerFactory; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.mutationtest.config.SettingsFactory; +import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.mutationtest.engine.MutationEngine; import org.pitest.mutationtest.execute.MutationAnalysisExecutor; import org.pitest.mutationtest.incremental.HistoryListener; @@ -133,7 +134,15 @@ public CombinedStatistics runReport() throws IOException { return emptyStatistics(); } - return runAnalysis(runtime, t0, args, engine, issues); + // Extract mutants from analysis units. Advanced history implementations can + // use this data to reduce the number of tests run during coverage. + // This is list of mutants is potentially larger than the one finally + // assessed, as no filters have been run across it. + List unfilteredMutants = preScanMutations.stream() + .flatMap(unit -> unit.mutants().stream()) + .collect(Collectors.toList()); + + return runAnalysis(runtime, t0, args, engine, issues, unfilteredMutants); } @@ -142,11 +151,11 @@ private CombinedStatistics emptyStatistics() { return new CombinedStatistics(mutationStatistics, new CoverageSummary(0,0), Collections.emptyList()); } - private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments args, MutationEngine engine, List issues) { + private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments args, MutationEngine engine, List issues, List unfilteredMutants) { History history = this.strategies.history(); history.initialize(); - CoverageDatabase coverageData = coverage().calculateCoverage(history.limitTests()); + CoverageDatabase coverageData = coverage().calculateCoverage(history.limitTests(unfilteredMutants)); history.processCoverage(coverageData); LOG.fine("Used memory after coverage calculation " @@ -154,7 +163,6 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments LOG.fine("Free Memory after coverage calculation " + (runtime.freeMemory() / MB) + " mb"); - final MutationStatisticsListener stats = new MutationStatisticsListener(); this.timings.registerStart(Timings.Stage.BUILD_MUTATION_TESTS); final List tus = buildMutationTests(coverageData, history, @@ -169,8 +177,10 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments + " mb"); ReportCoverage modifiedCoverage = transformCoverage(coverageData); + final MutationStatisticsListener stats = new MutationStatisticsListener(); final List config = createConfig(t0, modifiedCoverage, history, stats, engine, issues); + final MutationAnalysisExecutor mae = new MutationAnalysisExecutor( numberOfThreads(), resultInterceptor(), config); this.timings.registerStart(Timings.Stage.RUN_MUTATION_TESTS); @@ -353,7 +363,8 @@ private List buildMutationTests(CoverageDatabase coverageD final MutationGrouper grouper = this.settings.getMutationGrouper().makeFactory( this.data.getFreeFormProperties(), this.code, this.data.getNumberOfThreads(), this.data.getMutationUnitSize()); - final MutationTestBuilder builder = new MutationTestBuilder(wf, history, + + final MutationTestBuilder builder = new MutationTestBuilder(data.mode(), wf, history, source, grouper); return builder.createMutationTestUnits(this.code.getCodeUnderTestNames()); 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 28245dd8f..ff78a705c 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java @@ -19,6 +19,7 @@ import static org.pitest.mutationtest.DetectionStatus.KILLED; import static org.pitest.mutationtest.DetectionStatus.MEMORY_ERROR; import static org.pitest.mutationtest.DetectionStatus.NON_VIABLE; +import static org.pitest.mutationtest.DetectionStatus.NOT_STARTED; import static org.pitest.mutationtest.DetectionStatus.NO_COVERAGE; import static org.pitest.mutationtest.DetectionStatus.SURVIVED; import static org.pitest.mutationtest.DetectionStatus.TIMED_OUT; @@ -68,6 +69,7 @@ import org.pitest.mutationtest.build.PercentAndConstantTimeoutStrategy; import org.pitest.mutationtest.build.WorkerFactory; import org.pitest.mutationtest.config.DefaultDependencyPathPredicate; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.mutationtest.config.TestPluginArguments; import org.pitest.mutationtest.engine.MutationEngine; @@ -202,7 +204,19 @@ public void shouldRecordCorrectLineNumberForMutations() { verifyLineNumbers(111); } - private void run(final Class clazz, final Class test, + @Test + public void dryRunModeMarksMutantsAsNotStarted() { + run(OneMutationOnly.class, OneMutationFullTest.class, ExecutionMode.DRY_RUN, + "PRIMITIVE_RETURNS"); + verifyResults(NOT_STARTED); + } + + private void run(Class clazz, Class test, + final String ... mutators) { + run (clazz, test,ExecutionMode.NORMAL, mutators); + } + + private void run(Class clazz, Class test, ExecutionMode mode, final String ... mutators) { final ReportOptions data = new ReportOptions(); @@ -219,15 +233,16 @@ private void run(final Class clazz, final Class test, final JavaAgent agent = new JarCreatingJarFinder(); try { - createEngineAndRun(data, agent, Arrays.asList(mutators)); + createEngineAndRun(data, mode, agent, Arrays.asList(mutators)); } finally { agent.close(); } } - private void createEngineAndRun(final ReportOptions data, - final JavaAgent agent, - final Collection mutators) { + private void createEngineAndRun(ReportOptions data, + ExecutionMode mode, + JavaAgent agent, + Collection mutators) { final CoverageOptions coverageOptions = createCoverageOptions(data); @@ -278,7 +293,7 @@ null, coverageOptions, launchOptions, code, new NullCoverageExporter(), - final MutationTestBuilder builder = new MutationTestBuilder(wf, + final MutationTestBuilder builder = new MutationTestBuilder(mode, wf, new NullHistory(), source, new DefaultGrouper(0)); final List tus = builder diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/build/AnalyisPriorityComparatorTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/build/AnalyisPriorityComparatorTest.java index fe54cea06..efed31552 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/build/AnalyisPriorityComparatorTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/build/AnalyisPriorityComparatorTest.java @@ -3,10 +3,13 @@ import static org.junit.Assert.assertEquals; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; import org.junit.Test; import org.pitest.mutationtest.MutationMetaData; +import org.pitest.mutationtest.engine.MutationDetails; public class AnalyisPriorityComparatorTest { @@ -50,6 +53,11 @@ public MutationMetaData call() throws Exception { return null; } + @Override + public Collection mutants() { + return Collections.emptyList(); + } + }; } diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestBuilderTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestBuilderTest.java index 0699388ac..2c206ee7b 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestBuilderTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/build/MutationTestBuilderTest.java @@ -16,6 +16,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.pitest.classinfo.ClassName; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.engine.MutationDetails; import org.pitest.mutationtest.incremental.NullHistory; @@ -91,7 +92,7 @@ private void assertCreatesOneTestUnitForTwoMutations() { } private void makeTesteeWithUnitSizeOf(int unitSize) { - this.testee = new MutationTestBuilder(this.wf, new NullHistory(), + this.testee = new MutationTestBuilder(ExecutionMode.NORMAL, this.wf, new NullHistory(), this.source, new DefaultGrouper(unitSize)); } 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 f4ea301f1..d2dc45cc3 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 @@ -18,6 +18,7 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -112,7 +113,7 @@ public void setUp() { when( this.listenerFactory.getListener(any(), any(ListenerArguments.class))).thenReturn(this.listener); - when(history.limitTests()).thenReturn(c -> true); + when(history.limitTests(anyList())).thenReturn(c -> true); mockMutationEngine(); } diff --git a/pitest-maven/src/main/java/org/pitest/maven/AbstractPitMojo.java b/pitest-maven/src/main/java/org/pitest/maven/AbstractPitMojo.java index f2560cc0f..746e65278 100644 --- a/pitest-maven/src/main/java/org/pitest/maven/AbstractPitMojo.java +++ b/pitest-maven/src/main/java/org/pitest/maven/AbstractPitMojo.java @@ -366,6 +366,9 @@ public class AbstractPitMojo extends AbstractMojo { @Parameter(property = "pit.additionalTestSources", defaultValue = "src/test/kotlin") private List additionalTestSources; + @Parameter(property = "pit.dryRun", defaultValue = "false") + private boolean dryRun; + /** * The base directory of a multi-module project. Defaults to the execution * directory @@ -831,6 +834,10 @@ public List allProjects() { return session.getProjects(); } + public boolean isDryRun() { + return this.dryRun; + } + static class RunDecision { private List reasons = new ArrayList<>(4); diff --git a/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java b/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java index b90da4f20..1042e0c76 100644 --- a/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java +++ b/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java @@ -28,6 +28,7 @@ import org.pitest.classinfo.ClassName; import org.pitest.classpath.DirectoryClassPathRoot; import org.pitest.functional.FCollection; +import org.pitest.mutationtest.config.ExecutionMode; import org.pitest.mutationtest.config.ReportOptions; import org.pitest.testapi.TestGroupConfig; import org.pitest.util.Glob; @@ -272,6 +273,10 @@ private ReportOptions parseReportOptions(final List classPath) { data.setProjectBase(FileSystems.getDefault().getPath(this.mojo.getProjectBase())); } + if (this.mojo.isDryRun()) { + data.setExecutionMode(ExecutionMode.DRY_RUN); + } + checkForObsoleteOptions(this.mojo); return data; diff --git a/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java b/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java index 3b741cc1c..57f28d5e1 100644 --- a/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java +++ b/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.pitest.mutationtest.config.ExecutionMode.DRY_RUN; import static org.pitest.util.Verbosity.DEFAULT; import static org.pitest.util.Verbosity.QUIET; import static org.pitest.util.Verbosity.VERBOSE; @@ -485,6 +486,11 @@ public void testAddsModulesToMutationPathWhenCrossModule() { assertThat(actual.getCodePaths()).doesNotContain("barbuild"); } + public void testSetsDryRunMode() { + ReportOptions actual = parseConfig("true"); + assertThat(actual.mode()).isEqualTo(DRY_RUN); + } + private static MavenProject project(String group, String artefact) { MavenProject dependedOn = new MavenProject(); dependedOn.setGroupId(group);