Skip to content

Commit

Permalink
introduce dry run mode
Browse files Browse the repository at this point in the history
  • Loading branch information
hcoles committed Dec 13, 2024
1 parent 116ef37 commit d32d900
Show file tree
Hide file tree
Showing 15 changed files with 193 additions and 20 deletions.
13 changes: 8 additions & 5 deletions pitest-ant/src/main/java/org/pitest/ant/PitestTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}



}
13 changes: 13 additions & 0 deletions pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> {

private final String[] expectedPaths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -152,6 +154,7 @@ public class OptionsParser {
private final OptionSpec<File> projectBaseSpec;
private final OptionSpec<String> inputEncoding;
private final OptionSpec<String> outputEncoding;
private final ArgumentAcceptingOptionSpec<Boolean> dryRunSpec;

public OptionsParser(Predicate<String> dependencyFilter) {

Expand Down Expand Up @@ -407,6 +410,12 @@ public OptionsParser(Predicate<String> 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) {
Expand Down Expand Up @@ -506,6 +515,8 @@ private ParseResult parseCommandLine(final ReportOptions data,

setEncoding(data, userArgs);

configureExecutionMode(data, userArgs);

if (userArgs.has(projectBaseSpec)) {
data.setProjectBase(this.projectBaseSpec.value(userArgs).toPath());
}
Expand Down Expand Up @@ -533,6 +544,14 @@ private void configureVerbosity(ReportOptions data, OptionSet userArgs) {

}

private void configureExecutionMode(ReportOptions data, OptionSet userArgs) {
boolean isDryRun = (userArgs.has(this.dryRunSpec) && !userArgs.hasArgument(this.dryRunSpec))
|| this.dryRunSpec.value(userArgs);
if (isDryRun) {
data.setExecutionMode(ExecutionMode.DRY_RUN);
}
}

private void setClassPath(final OptionSet userArgs, final ReportOptions data) {

final List<String> elements = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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<MutationDetails> mutations;

public DryRunUnit(final Collection<MutationDetails> mutations) {
this.mutations = mutations;
}

@Override
public MutationMetaData call() throws Exception {
LOG.fine("Not analysing " + this.mutations.size()
+ " mutations as in dry run");
List<MutationResult> 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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -109,7 +113,10 @@ private MutationAnalysisUnit makePreAnalysedUnit(
}

private MutationAnalysisUnit makeUnanalysedUnit(
final Collection<MutationDetails> needAnalysis) {
Collection<MutationDetails> needAnalysis) {
if (mode == ExecutionMode.DRY_RUN) {
return new DryRunUnit(needAnalysis);
}
return new MutationTestUnit(needAnalysis, this.workerFactory);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.pitest.mutationtest.config;

public enum ExecutionMode {
NORMAL, DRY_RUN
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ public class ReportOptions {

private boolean arcmutateMissing = true;

private ExecutionMode mode = ExecutionMode.NORMAL;

// currently used only via maven
private Map<String,String> environmentVariables = new HashMap<>();

Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,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<MutationAnalysisUnit> tus = buildMutationTests(coverageData, history,
Expand All @@ -169,8 +168,10 @@ private CombinedStatistics runAnalysis(Runtime runtime, long t0, EngineArguments
+ " mb");

ReportCoverage modifiedCoverage = transformCoverage(coverageData);
final MutationStatisticsListener stats = new MutationStatisticsListener();
final List<MutationResultListener> config = createConfig(t0, modifiedCoverage, history,
stats, engine, issues);

final MutationAnalysisExecutor mae = new MutationAnalysisExecutor(
numberOfThreads(), resultInterceptor(), config);
this.timings.registerStart(Timings.Stage.RUN_MUTATION_TESTS);
Expand Down Expand Up @@ -353,7 +354,8 @@ private List<MutationAnalysisUnit> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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<String> mutators) {
private void createEngineAndRun(ReportOptions data,
ExecutionMode mode,
JavaAgent agent,
Collection<String> mutators) {

final CoverageOptions coverageOptions = createCoverageOptions(data);

Expand Down Expand Up @@ -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<MutationAnalysisUnit> tus = builder
Expand Down
Loading

0 comments on commit d32d900

Please sign in to comment.