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 e08a8cf61..70cc2b7db 100644 --- a/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java +++ b/pitest-ant/src/main/java/org/pitest/ant/PitestTask.java @@ -124,10 +124,6 @@ public void setTargetTests(final String value) { this.setOption(ConfigOption.TEST_FILTER, value); } - public void setDependencyDistance(final String value) { - this.setOption(ConfigOption.DEPENDENCY_DISTANCE, value); - } - public void setThreads(final String value) { this.setOption(ConfigOption.THREADS, value); } 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 9fedd0a22..038ca4488 100644 --- a/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java +++ b/pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java @@ -73,13 +73,6 @@ public void shouldPassAvoidCallsOptionToJavaTask() { verify(this.arg).setValue("--avoidCallsTo=avoidCalls"); } - @Test - public void shouldPassDependencyDistanceOptionToJavaTask() { - this.pitestTask.setDependencyDistance("distance"); - this.pitestTask.execute(this.java); - verify(this.arg).setValue("--dependencyDistance=distance"); - } - @Test public void shouldPassExcludedClassesOptionToJavaTask() { this.pitestTask.setExcludedClasses("String"); 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 db359a5a1..afda79cbc 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 @@ -49,7 +49,6 @@ 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.DEPENDENCY_DISTANCE; 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; @@ -102,7 +101,6 @@ public class OptionsParser { private final OptionSpec targetClassesSpec; private final OptionSpec targetTestsSpec; private final OptionSpec avoidCallsSpec; - private final OptionSpec depth; private final OptionSpec threadsSpec; private final OptionSpec sourceDirSpec; private final OptionSpec historyOutputSpec; @@ -184,11 +182,6 @@ public OptionsParser(Predicate dependencyFilter) { .describedAs( "comma separated list of filters to match against tests to run"); - this.depth = parserAccepts(DEPENDENCY_DISTANCE).withRequiredArg() - .ofType(Integer.class) - .defaultsTo(DEPENDENCY_DISTANCE.getDefault(Integer.class)) - .describedAs("maximum distance to look from test for covered classes"); - this.threadsSpec = parserAccepts(THREADS).withRequiredArg() .ofType(Integer.class).defaultsTo(THREADS.getDefault(Integer.class)) .describedAs("number of threads to use for testing"); @@ -422,7 +415,7 @@ private ParseResult parseCommandLine(final ReportOptions data, data.setSourceDirs(this.sourceDirSpec.values(userArgs)); data.setMutators(this.mutators.values(userArgs)); data.setFeatures(this.features.values(userArgs)); - data.setDependencyAnalysisMaxDistance(this.depth.value(userArgs)); + data.addChildJVMArgs(this.jvmArgsProcessor.values(userArgs)); data.setFullMutationMatrix(this.fullMutationMatrixSpec.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 e1bac4513..89b073b28 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 @@ -96,13 +96,6 @@ public void shouldParseCommaSeparatedListOfSourceDirectories() { assertEquals(Arrays.asList(new File("foo/bar"), new File("bar/far")), actual.getSourceDirs()); } - @Test - public void shouldParseMaxDepenencyDistance() { - final ReportOptions actual = parseAddingRequiredArgs( - "--dependencyDistance", "42"); - assertEquals(42, actual.getDependencyAnalysisMaxDistance()); - } - @Test public void shouldParseCommaSeparatedListOfJVMArgs() { final ReportOptions actual = parseAddingRequiredArgs("--jvmArgs", "foo,bar"); 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 5faf10e94..e90331e21 100644 --- a/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java +++ b/pitest-entry/src/main/java/org/pitest/classpath/CodeSource.java @@ -61,10 +61,6 @@ public ClassPath getClassPath() { return this.classPath.getClassPath(); } - public ProjectClassPaths getProjectPaths() { - return this.classPath; - } - public Optional findTestee(final String className) { final TestToClassMapper mapper = new TestToClassMapper(this.classRepository); return mapper.findTestee(className); 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 8e479dd2f..af9ca8c25 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java @@ -189,6 +189,11 @@ private void checkForFailedTest(final CoverageResult cr) { private TestInfo createTestInfo(final Description description, final int executionTime, final int linesCovered) { + + if (description.getFirstTestClass() == null) { + System.out.println(description); + } + final Optional testee = this.code.findTestee(description .getFirstTestClass()); return new TestInfo(description.getFirstTestClass(), diff --git a/pitest-entry/src/main/java/org/pitest/coverage/execute/CoverageProcess.java b/pitest-entry/src/main/java/org/pitest/coverage/execute/CoverageProcess.java index 976ca6104..8cabb735f 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/execute/CoverageProcess.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/execute/CoverageProcess.java @@ -17,8 +17,7 @@ public class CoverageProcess { public CoverageProcess(final ProcessArgs processArgs, final CoverageOptions arguments, final ServerSocket socket, - final List testClases, final Consumer handler) - throws IOException { + final List testClases, final Consumer handler) { this.process = new WrappingProcess(socket.getLocalPort(), processArgs, CoverageMinion.class); this.crt = new CoverageCommunicationThread(socket, arguments, testClases, @@ -30,7 +29,7 @@ public void start() throws IOException, InterruptedException { this.process.start(); } - public ExitCode waitToDie() throws InterruptedException { + public ExitCode waitToDie() { try { return this.crt.waitToFinish(); } finally { 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 842999734..976750112 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 @@ -48,10 +48,7 @@ public enum ConfigOption { * Features to enable/disable */ FEATURES("features"), - /** - * Maximum number of hops from a mutable class to a test - */ - DEPENDENCY_DISTANCE("dependencyDistance", -1), + /** * Arguments to launch child processes with */ 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 63cecfb16..afab173c9 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 @@ -96,8 +96,6 @@ public class ReportOptions { private Collection mutators; private Collection features; - private int dependencyAnalysisMaxDistance; - private final List jvmArgs = new ArrayList<>(DEFAULT_CHILD_JVM_ARGS); private int numberOfThreads = 0; private float timeoutFactor = PercentAndConstantTimeoutStrategy.DEFAULT_FACTOR; @@ -213,22 +211,6 @@ public void setFeatures(Collection features) { this.features = features; } - /** - * @return the dependencyAnalysisMaxDistance - */ - public int getDependencyAnalysisMaxDistance() { - return this.dependencyAnalysisMaxDistance; - } - - /** - * @param dependencyAnalysisMaxDistance - * the dependencyAnalysisMaxDistance to set - */ - public void setDependencyAnalysisMaxDistance( - final int dependencyAnalysisMaxDistance) { - this.dependencyAnalysisMaxDistance = dependencyAnalysisMaxDistance; - } - public List getJvmArgs() { return this.jvmArgs; } @@ -661,7 +643,6 @@ public String toString() { .add("classPathElements=" + classPathElements) .add("mutators=" + mutators) .add("features=" + features) - .add("dependencyAnalysisMaxDistance=" + dependencyAnalysisMaxDistance) .add("jvmArgs=" + jvmArgs) .add("numberOfThreads=" + numberOfThreads) .add("timeoutFactor=" + timeoutFactor) 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 1ca422855..eadbe1fd7 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 @@ -135,8 +135,7 @@ public TestPrioritiserFactory getTestPrioritiser() { public CoverageOptions createCoverageOptions() { return new CoverageOptions( this.options.getTargetClasses(), this.options.getExcludedClasses(), - this.options.createMinionSettings(), this.options.getVerbosity(), - this.options.getDependencyAnalysisMaxDistance()); + this.options.createMinionSettings(), this.options.getVerbosity()); } public CompoundInterceptorFactory getInterceptor() { diff --git a/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/ATesteeClass.java b/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/ATesteeClass.java new file mode 100644 index 000000000..dcc1b5795 --- /dev/null +++ b/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/ATesteeClass.java @@ -0,0 +1,11 @@ +package com.example.coverage.execute.samples.executionindiscovery; + +public class ATesteeClass { + + public String foo(int i) { + if (i > 10) { + return "fuzz"; + } + return "bizz"; + } +} diff --git a/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/AnExecutingTest.java b/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/AnExecutingTest.java new file mode 100644 index 000000000..1dedbc160 --- /dev/null +++ b/pitest-entry/src/test/java/com/example/coverage/execute/samples/executionindiscovery/AnExecutingTest.java @@ -0,0 +1,13 @@ +package com.example.coverage.execute.samples.executionindiscovery; + +import org.pitest.executingtest.ExecutingTest; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AnExecutingTest { + @ExecutingTest + public void aTest() { + ATesteeClass a = new ATesteeClass(); + assertThat(a.foo(1)).isEqualTo("bizz"); + } +} diff --git a/pitest-entry/src/test/java/org/pitest/coverage/execute/CoverageProcessSystemTest.java b/pitest-entry/src/test/java/org/pitest/coverage/execute/CoverageProcessSystemTest.java index ff080c54c..513fe1ffe 100644 --- a/pitest-entry/src/test/java/org/pitest/coverage/execute/CoverageProcessSystemTest.java +++ b/pitest-entry/src/test/java/org/pitest/coverage/execute/CoverageProcessSystemTest.java @@ -7,6 +7,7 @@ import com.example.coverage.execute.samples.exceptions.ThrowsExceptionFromLargeMethodTestee; import com.example.coverage.execute.samples.exceptions.ThrowsExceptionInFinallyBlockTestee; import com.example.coverage.execute.samples.exceptions.ThrowsExceptionTestee; +import com.example.coverage.execute.samples.executionindiscovery.AnExecutingTest; import com.example.coverage.execute.samples.simple.ParentChildInitializationTest; import com.example.coverage.execute.samples.simple.Testee; import com.example.coverage.execute.samples.simple.Testee2; @@ -31,7 +32,6 @@ import org.pitest.util.SocketFinder; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; @@ -42,7 +42,6 @@ import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; @@ -243,7 +242,7 @@ public void testNewLine() throws IOException { } @Test - public void shouldNotCorruptedTheSystemNewLineProperty() throws Exception { + public void shouldNotCorruptTheSystemNewLineProperty() throws Exception { final List coveredClasses = runCoverageForTest(ReliesOnNewLineTest.class); assertThat(coveredClasses).noneMatch(failingTest()); } @@ -255,13 +254,11 @@ public void handlesParentChildInitializationOrderIssues() throws Exception { .anyMatch(coverageFor(ClassName.fromString("com.example.coverage.execute.samples.simple.TesteeChild"))); } - private ClassPath classPathWithoutJUnit() { - final List cpWithoutJUnit = - ClassPath.getClassPathElementsAsFiles().stream() - .filter(file -> !file.getName().contains("junit")) - .collect(Collectors.toList()); - - return new ClassPath(cpWithoutJUnit); + @Test + public void gathersCoverageWhenTestsExecutedDuringDiscovery() throws Exception { + final List coveredClasses = runCoverageForTest(AnExecutingTest.class); + assertThat(coveredClasses) + .anyMatch(coverageFor(ClassName.fromString("com.example.coverage.execute.samples.executionindiscovery.ATesteeClass"))); } private Predicate failingTest() { @@ -282,7 +279,7 @@ private void runCoverageProcess(final Class test, InterruptedException { final Consumer handler = a -> coveredClasses.add(a); - final CoverageOptions sa = new CoverageOptions(coverOnlyTestees(), excludeTests(), TestPluginArguments.defaults(), VERBOSE, -1); + final CoverageOptions sa = new CoverageOptions(coverOnlyTestees(), excludeTests(), TestPluginArguments.defaults(), VERBOSE); final JarCreatingJarFinder agent = new JarCreatingJarFinder(); try { diff --git a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationCoverageReportSystemTest.java b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationCoverageReportSystemTest.java index 5d8940fdd..725650af3 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/MutationCoverageReportSystemTest.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/MutationCoverageReportSystemTest.java @@ -78,15 +78,6 @@ public void shouldPickRelevantTestsAndKillMutationsBasedOnCoverageData() { verifyResults(KILLED); } - @Test - public void shouldPickRelevantTestsAndKillMutationsBasedOnCoverageDataWhenLimitedByClassReach() { - this.data.setDependencyAnalysisMaxDistance(2); - this.data.setTargetTests(predicateFor("com.example.*FullyCovered*")); - this.data.setTargetClasses(asList("com.example.FullyCovered*")); - createAndRun(); - verifyResults(KILLED); - } - @Test public void shouldReportUnCoveredMutations() { this.data.setTargetClasses(asList("com.example.PartiallyCovered*")); @@ -254,7 +245,6 @@ public void shouldMutateClassesSuppliedToAlternateClassPath() cp.add(location); this.data.setClassPathElements(cp); - this.data.setDependencyAnalysisMaxDistance(-1); this.data.setExcludedClasses(asList("*Power*", "*JMockit*")); createAndRun(); verifyResults(KILLED); 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 80cbe6a9b..1dd6c15d1 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/ReportTestBase.java @@ -139,8 +139,7 @@ code, this.data, new SettingsFactory(this.data, this.plugins), private CoverageOptions createCoverageOptions(TestPluginArguments configuration) { return new CoverageOptions(this.data.getTargetClasses(),this.data.getExcludedClasses(), - configuration, this.data.getVerbosity(), - this.data.getDependencyAnalysisMaxDistance()); + configuration, this.data.getVerbosity()); } protected void setMutators(final String mutator) { 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 7646eb5f9..7604c80da 100644 --- a/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java +++ b/pitest-entry/src/test/java/org/pitest/mutationtest/TestMutationTesting.java @@ -212,7 +212,6 @@ private void run(final Class clazz, final Class test, final Set> tests = Collections.singleton(isEqual(test.getName())); data.setTargetTests(tests); - data.setDependencyAnalysisMaxDistance(-1); final Set mutees = Collections.singleton(clazz.getName() + "*"); data.setTargetClasses(mutees); @@ -295,7 +294,7 @@ null, coverageOptions, launchOptions, code, new NullCoverageExporter(), private CoverageOptions createCoverageOptions(ReportOptions data) { return new CoverageOptions(data.getTargetClasses(),data.getExcludedClasses(), this.config, - data.getVerbosity(), data.getDependencyAnalysisMaxDistance()); + data.getVerbosity()); } protected void verifyResults(final DetectionStatus... detectionStatus) { 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 2b0000b44..bd2a2c936 100755 --- a/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java +++ b/pitest-maven-verification/src/test/java/org/pitest/PitMojoIT.java @@ -99,6 +99,7 @@ public void shouldProduceConsistantCoverageData() throws Exception { } @Test + @Ignore // debatable if this test should be here. Relies on external testng plugin public void shouldWorkWithTestNG() throws Exception { File testDir = prepare("/pit-testng"); @@ -394,6 +395,7 @@ public void shouldWorkWithYatspec() throws Exception { } @Test + @Ignore // note this test depends on the junit5 plugin public void shouldWorkWithQuarkus() throws Exception { assumeTrue(CurrentRuntime.version() >= 11); 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 60e2fcecf..26facf355 100644 --- a/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java +++ b/pitest-maven/src/main/java/org/pitest/maven/MojoToReportOptionsConverter.java @@ -97,7 +97,7 @@ private ReportOptions parseReportOptions(final List classPath) { data.setUseClasspathJar(this.mojo.isUseClasspathJar()); data.setClassPathElements(classPath); - data.setDependencyAnalysisMaxDistance(this.mojo.getMaxDependencyDistance()); + data.setFailWhenNoMutations(shouldFailWhenNoMutations()); data.setTargetClasses(determineTargetClasses()); 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 ba3f2a49d..23dd493a6 100644 --- a/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java +++ b/pitest-maven/src/test/java/org/pitest/maven/MojoToReportOptionsConverterTest.java @@ -94,11 +94,6 @@ public void testUsesSourceDirectoriesFromProject() { actual.getSourceDirs()); } - public void testParsesMaxDependencyDistance() { - final ReportOptions actual = parseConfig("42"); - assertEquals(42, actual.getDependencyAnalysisMaxDistance()); - } - public void testParsesExcludedRunners() { String runner = "org.springframework.test.context.junit4.SpringJUnit4ClassRunner"; final ReportOptions actual = parseConfig("" + runner + ""); diff --git a/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java b/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java index f99632d78..cfba6f81f 100644 --- a/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java +++ b/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java @@ -16,10 +16,8 @@ import org.pitest.boot.HotSwapAgent; import org.pitest.classinfo.ClassName; -import org.pitest.classpath.ClassPathByteArraySource; import org.pitest.classpath.ClassloaderByteArraySource; import org.pitest.coverage.CoverageTransformer; -import org.pitest.dependency.DependencyExtractor; import org.pitest.functional.prelude.Prelude; import org.pitest.help.PitHelpError; import org.pitest.mutationtest.config.ClientPluginServices; @@ -27,7 +25,9 @@ import org.pitest.mutationtest.mocksupport.BendJavassistToMyWillTransformer; import org.pitest.mutationtest.mocksupport.JavassistInputStreamInterceptorAdapater; import org.pitest.testapi.Configuration; +import org.pitest.testapi.ExecutedInDiscovery; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.execute.FindTestUnits; import org.pitest.util.ExitCode; import org.pitest.util.Glob; @@ -79,13 +79,22 @@ public static void main(final String[] args) { HotSwapAgent.addTransformer(new CoverageTransformer( convertToJVMClassFilter(paramsFromParent.getFilter()))); - final List tus = getTestsFromParent(dis, paramsFromParent); + final List tus = getTestsFromParent(dis, paramsFromParent, invokeQueue); - LOG.info(() -> tus.size() + " tests received"); + LOG.info(() -> tus.size() + " tests discovered"); - final CoverageWorker worker = new CoverageWorker(invokeQueue, tus); + // If we have more than one test plugin on the classpath we may have a mix + // of tests executed during discovery (JUnit 5) and still requiring execution + // (junit4, testng and JUnit5 tests accelerated by arcmutate) + List toExecute = removeTestsExecutedDuringDiscovery(tus); - worker.run(); + if (!toExecute.isEmpty()) { + LOG.info(() -> tus.size() + "Executing " + toExecute.size() + " tests not run during discovery."); + CoverageWorker worker = new CoverageWorker(invokeQueue, toExecute); + worker.run(); + } else { + LOG.info(() -> tus.size() + "All tests were executed as part of discovery."); + } } catch (final PitHelpError phe) { LOG.log(Level.SEVERE, phe.getMessage()); @@ -112,6 +121,13 @@ public static void main(final String[] args) { } + private static List removeTestsExecutedDuringDiscovery(List tus) { + List toExecute = tus.stream() + .filter(t -> !(t instanceof ExecutedInDiscovery)) + .collect(Collectors.toList()); + return toExecute; + } + private static void enablePowerMockSupport() { // Bwahahahahahahaha HotSwapAgent.addTransformer(new BendJavassistToMyWillTransformer(Prelude @@ -125,38 +141,30 @@ private static Predicate convertToJVMClassFilter( } private static List getTestsFromParent( - final SafeDataInputStream dis, final CoverageOptions paramsFromParent) { + final SafeDataInputStream dis, final CoverageOptions paramsFromParent, CoveragePipe invokeQueue) { final List classes = receiveTestClassesFromParent(dis); Collections.sort(classes); // ensure classes loaded in a consistent order final Configuration testPlugin = createTestPlugin(paramsFromParent); verifyEnvironment(testPlugin); - final List tus = discoverTests(testPlugin, classes); + final List tus = discoverTests(testPlugin, classes, invokeQueue); if (tus.isEmpty()) { LOG.warning("No executable tests were found after examining the " + classes.size() + " test classes supplied. This may indicate an issue with the classpath or a missing test plugin (e.g for JUnit 5)."); } - final DependencyFilter filter = new DependencyFilter( - new DependencyExtractor(new ClassPathByteArraySource(), - paramsFromParent.getDependencyAnalysisMaxDistance()), - paramsFromParent.getFilter()); - final List filteredTus = filter - .filterTestsByDependencyAnalysis(tus); - - LOG.info(() -> "Dependency analysis reduced number of potential tests by " - + (tus.size() - filteredTus.size())); - return filteredTus; - + return tus; } - private static List discoverTests(final Configuration testPlugin, - final List classes) { - final FindTestUnits finder = new FindTestUnits(testPlugin); - final List tus = finder - .findTestUnitsForAllSuppliedClasses(classes.stream().flatMap(ClassName.nameToClass()).collect(Collectors.toList())); + private static List discoverTests(Configuration testPlugin, List classes, CoveragePipe invokeQueue) { + TestUnitExecutionListener listener = new CoverageTestExecutionListener(invokeQueue); + FindTestUnits finder = new FindTestUnits(testPlugin, listener); + List tus = finder + .findTestUnitsForAllSuppliedClasses(classes.stream() + .flatMap(ClassName.nameToClass()) + .collect(Collectors.toList())); LOG.info(() -> "Found " + tus.size() + " tests"); return tus; } diff --git a/pitest/src/main/java/org/pitest/coverage/execute/CoverageOptions.java b/pitest/src/main/java/org/pitest/coverage/execute/CoverageOptions.java index b6e315b6c..36fcb9959 100644 --- a/pitest/src/main/java/org/pitest/coverage/execute/CoverageOptions.java +++ b/pitest/src/main/java/org/pitest/coverage/execute/CoverageOptions.java @@ -34,17 +34,15 @@ public class CoverageOptions implements Serializable { private final Collection exclude; private final Verbosity verbosity; private final TestPluginArguments pitConfig; - private final int maxDependencyDistance; + public CoverageOptions(final Collection include, final Collection exclude, - final TestPluginArguments pitConfig, final Verbosity verbose, - final int maxDependencyDistance) { + final TestPluginArguments pitConfig, final Verbosity verbose) { Objects.requireNonNull(pitConfig); this.include = include; this.exclude = exclude; this.verbosity = verbose; this.pitConfig = pitConfig; - this.maxDependencyDistance = maxDependencyDistance; } public Predicate getFilter() { @@ -61,10 +59,6 @@ public TestPluginArguments getPitConfig() { return this.pitConfig; } - public int getDependencyAnalysisMaxDistance() { - return this.maxDependencyDistance; - } - private static Predicate commonClasses() { return Prelude.or( glob("org.pitest.*"), diff --git a/pitest/src/main/java/org/pitest/coverage/execute/CoverageTestExecutionListener.java b/pitest/src/main/java/org/pitest/coverage/execute/CoverageTestExecutionListener.java new file mode 100644 index 000000000..309a80f5b --- /dev/null +++ b/pitest/src/main/java/org/pitest/coverage/execute/CoverageTestExecutionListener.java @@ -0,0 +1,50 @@ +package org.pitest.coverage.execute; + +import org.pitest.coverage.CoverageReceiver; +import org.pitest.testapi.Description; +import org.pitest.testapi.TestUnitExecutionListener; +import org.pitest.util.Log; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.logging.Logger; + +public class CoverageTestExecutionListener implements TestUnitExecutionListener { + + private static final Logger LOG = Log.getLogger(); + private final ThreadMXBean threads = ManagementFactory.getThreadMXBean(); + + private final CoverageReceiver invokeQueue; + private long t0; + private int threadsBeforeTest; + + public CoverageTestExecutionListener(CoverageReceiver invokeQueue) { + this.invokeQueue = invokeQueue; + } + + @Override + public void executionStarted(Description description) { + LOG.fine(() -> "Gathering coverage for test " + description); + t0 = System.currentTimeMillis(); + threadsBeforeTest = this.threads.getThreadCount(); + } + + @Override + public void executionFinished(Description description, boolean passed) { + int executionTime = (int) (System.currentTimeMillis() - t0); + if (executionTime < 0) { + LOG.warning("Recorded negative test time. Test life cycle not as expected."); + // substitute an unimportant, but high, time for this test so it is unlikely to + // be prioritised above others. + executionTime = 120000; + } + + final int threadsAfterTest = this.threads.getThreadCount(); + if (threadsAfterTest > threadsBeforeTest) { + LOG.warning("More threads at end of test (" + threadsAfterTest + ") " + + description + " than start. (" + + threadsBeforeTest + ")"); + } + this.invokeQueue.recordTestOutcome(description, passed, executionTime); + } +} diff --git a/pitest/src/main/java/org/pitest/coverage/execute/DependencyFilter.java b/pitest/src/main/java/org/pitest/coverage/execute/DependencyFilter.java deleted file mode 100644 index d5096e5a2..000000000 --- a/pitest/src/main/java/org/pitest/coverage/execute/DependencyFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.pitest.coverage.execute; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; - -import org.pitest.dependency.DependencyExtractor; -import org.pitest.functional.FCollection; -import org.pitest.testapi.TestUnit; -import org.pitest.util.Unchecked; - -class DependencyFilter { - - private final DependencyExtractor analyser; - private final Predicate filter; - - DependencyFilter(final DependencyExtractor analyser, - final Predicate filter) { - this.analyser = analyser; - this.filter = filter; - } - - List filterTestsByDependencyAnalysis(final List tus) { - if (this.analyser.getMaxDistance() < 0) { - return tus; - } else { - return FCollection.filter(tus, isWithinReach()); - } - } - - private Predicate isWithinReach() { - - return new Predicate() { - private final Map cache = new HashMap<>(); - - @Override - public boolean test(final TestUnit testUnit) { - final String testClass = testUnit.getDescription().getFirstTestClass(); - try { - if (this.cache.containsKey(testClass)) { - return this.cache.get(testClass); - } else { - final boolean inReach = !DependencyFilter.this.analyser - .extractCallDependenciesForPackages(testClass, - DependencyFilter.this.filter).isEmpty(); - this.cache.put(testClass, inReach); - return inReach; - } - - } catch (final IOException e) { - throw Unchecked.translateCheckedException(e); - } - } - - }; - } - -} diff --git a/pitest/src/main/java/org/pitest/dependency/DependencyAccess.java b/pitest/src/main/java/org/pitest/dependency/DependencyAccess.java deleted file mode 100644 index 557d00ffa..000000000 --- a/pitest/src/main/java/org/pitest/dependency/DependencyAccess.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2010 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import java.util.Objects; - -final class DependencyAccess { - - static class Member implements Comparable { - private final String owner; - private final String name; - - protected Member(final String owner, final String name) { - this.owner = owner; - this.name = name; - } - - public String getOwner() { - return this.owner; - } - - public String getName() { - return this.name; - } - - @Override - public int hashCode() { - return Objects.hash(owner, name); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final Member other = (Member) obj; - return Objects.equals(owner, other.owner) - && Objects.equals(name, other.name); - } - - @Override - public int compareTo(final Member other) { - return (other.name.compareTo(this.name) * 100) - + (other.owner.compareTo(this.owner) * 1000); - } - - } - - private final Member source; - private final Member dest; - - protected DependencyAccess(final Member source, final Member dest) { - this.source = source; - this.dest = dest; - } - - public Member getSource() { - return this.source; - } - - public Member getDest() { - return this.dest; - } - - @Override - public int hashCode() { - return Objects.hash(source, dest); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final DependencyAccess other = (DependencyAccess) obj; - return Objects.equals(source, other.source) - && Objects.equals(dest, other.dest); - } -} diff --git a/pitest/src/main/java/org/pitest/dependency/DependencyClassVisitor.java b/pitest/src/main/java/org/pitest/dependency/DependencyClassVisitor.java deleted file mode 100644 index 02bc5cb6a..000000000 --- a/pitest/src/main/java/org/pitest/dependency/DependencyClassVisitor.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2010 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.pitest.bytecode.ASMVersion; -import org.pitest.dependency.DependencyAccess.Member; - -import java.util.function.Consumer; - -class DependencyClassVisitor extends ClassVisitor { - - private final Consumer typeReceiver; - private String className; - - protected DependencyClassVisitor(final ClassVisitor visitor, - final Consumer typeReceiver) { - super(ASMVersion.ASM_VERSION, visitor); - this.typeReceiver = filterOutJavaLangObject(typeReceiver); - } - - private Consumer filterOutJavaLangObject( - final Consumer child) { - return a -> { - if (!a.getDest().getOwner().equals("java/lang/Object")) { - child.accept(a); - } - - }; - } - - @Override - public void visit(final int version, final int access, final String name, - final String signature, final String superName, final String[] interfaces) { - this.className = name; - } - - @Override - public MethodVisitor visitMethod(final int access, final String name, - final String desc, final String signature, final String[] exceptions) { - final MethodVisitor methodVisitor = this.cv.visitMethod(access, name, desc, - signature, exceptions); - - final Member me = new Member(this.className, name); - return new DependencyAnalysisMethodVisitor(me, methodVisitor, - this.typeReceiver); - } - - private static class DependencyAnalysisMethodVisitor extends MethodVisitor { - - private final Member member; - private final Consumer typeReceiver; - - DependencyAnalysisMethodVisitor(final Member member, - final MethodVisitor methodVisitor, - final Consumer typeReceiver) { - super(ASMVersion.ASM_VERSION, methodVisitor); - this.typeReceiver = typeReceiver; - this.member = member; - } - - @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc, boolean itf) { - this.typeReceiver.accept(new DependencyAccess(this.member, new Member( - owner, name))); - this.mv.visitMethodInsn(opcode, owner, name, desc, itf); - } - - @Override - public void visitFieldInsn(final int opcode, final String owner, - final String name, final String desc) { - this.typeReceiver.accept(new DependencyAccess(this.member, new Member( - owner, name))); - this.mv.visitFieldInsn(opcode, owner, name, desc); - } - } - -} diff --git a/pitest/src/main/java/org/pitest/dependency/DependencyExtractor.java b/pitest/src/main/java/org/pitest/dependency/DependencyExtractor.java deleted file mode 100644 index 324e15744..000000000 --- a/pitest/src/main/java/org/pitest/dependency/DependencyExtractor.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2010 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import org.objectweb.asm.ClassReader; -import org.pitest.bytecode.NullVisitor; -import org.pitest.classinfo.ClassByteArraySource; -import org.pitest.functional.FCollection; -import org.pitest.util.Functions; -import org.pitest.util.Log; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.logging.Logger; - -import static org.pitest.functional.prelude.Prelude.and; - -public class DependencyExtractor { - private static final Logger LOG = Log.getLogger(); - private final int depth; - private final ClassByteArraySource classToBytes; - - public DependencyExtractor(final ClassByteArraySource classToBytes, - final int depth) { - this.depth = depth; - this.classToBytes = classToBytes; - } - - public Collection extractCallDependenciesForPackages( - final String clazz, final Predicate targetPackages) - throws IOException { - final Set allDependencies = extractCallDependencies(clazz, - new IgnoreCoreClasses()); - return FCollection.filter(allDependencies, - and(asJVMNamePredicate(targetPackages), notSuppliedClass(clazz))); - } - - private static Predicate notSuppliedClass(final String clazz) { - return a -> !Functions.jvmClassToClassName().apply(a).equals(clazz); - } - - private static Predicate asJVMNamePredicate( - final Predicate predicate) { - return a -> predicate.test(Functions.jvmClassToClassName().apply(a)); - } - - public Collection extractCallDependenciesForPackages( - final String clazz, final Predicate targetPackages, - final Predicate doNotTraverse) throws IOException { - final Set allDependencies = extractCallDependencies(clazz, - doNotTraverse); - return FCollection.filter(allDependencies, targetPackages); - } - - Set extractCallDependencies(final String clazz, - final Predicate filter) throws IOException { - - return this - .extractCallDependencies(clazz, new TreeSet<>(), filter, 0); - } - - public int getMaxDistance() { - return this.depth; - } - - private Set extractCallDependencies(final String clazz, - final TreeSet visited, final Predicate filter, - final int currentDepth) throws IOException { - - final Map> classesToAccesses = groupDependenciesByClass(extractRelevantDependencies( - clazz, filter)); - final Set dependencies = new HashSet<>( - classesToAccesses.keySet()); - - dependencies.removeAll(visited); - visited.addAll(dependencies); - - if ((currentDepth < (this.depth - 1)) || (this.depth == 0)) { - - dependencies.addAll(examineChildDependencies(currentDepth, dependencies, - visited, filter)); - - } - - return dependencies; - - } - - private Set examineChildDependencies(final int currentDepth, - final Set classes, final TreeSet visited, - final Predicate filter) throws IOException { - - final Set deps = new HashSet<>(); - for (final String each : classes) { - final Set childDependencies = extractCallDependencies(each, - visited, filter, currentDepth + 1); - deps.addAll(childDependencies); - } - return deps; - } - - private Set extractRelevantDependencies(final String clazz, - final Predicate filter) throws IOException { - final List dependencies = extract(clazz, filter); - final Set relevantDependencies = new TreeSet<>( - equalDestinationComparator()); - FCollection.filter(dependencies, filter, relevantDependencies); - return relevantDependencies; - } - - private static Comparator equalDestinationComparator() { - return Comparator.comparing(DependencyAccess::getDest); - } - - private List extract(final String clazz, - final Predicate filter) { - final Optional bytes = this.classToBytes.getBytes(clazz); - if (!bytes.isPresent()) { - LOG.warning("No bytes found for " + clazz); - return Collections.emptyList(); - } - final ClassReader reader = new ClassReader(bytes.get()); - final List dependencies = new ArrayList<>(); - - final Consumer se = constructCollectingSideEffectForVisitor( - dependencies, and(nameIsEqual(clazz).negate(), filter)); - final DependencyClassVisitor dcv = new DependencyClassVisitor( - new NullVisitor(), se); - reader.accept(dcv, ClassReader.EXPAND_FRAMES); - return dependencies; - } - - private Map> groupDependenciesByClass( - final Set relevantDependencies) { - return FCollection.fold(addDependenciesToMap(), - new HashMap<>(), relevantDependencies); - - } - - private static BiFunction>, DependencyAccess, Map>> addDependenciesToMap() { - - return (map, access) -> { - - List list = map.get(access.getDest().getOwner()); - if (list == null) { - list = new ArrayList<>(); - } - list.add(access); - map.put(access.getDest().getOwner(), list); - return map; - }; - } - - private static Predicate nameIsEqual(final String clazz) { - return a -> a.getDest().getOwner().equals(clazz); - } - - private static Consumer constructCollectingSideEffectForVisitor( - final List dependencies, - final Predicate predicate) { - return a -> { - if (predicate.test(a)) { - dependencies.add(a); - } - }; - } - -} diff --git a/pitest/src/main/java/org/pitest/dependency/IgnoreCoreClasses.java b/pitest/src/main/java/org/pitest/dependency/IgnoreCoreClasses.java deleted file mode 100644 index cc0018028..000000000 --- a/pitest/src/main/java/org/pitest/dependency/IgnoreCoreClasses.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2011 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import java.util.Arrays; -import java.util.Collection; -import java.util.function.Predicate; - -import org.pitest.functional.prelude.Prelude; -import org.pitest.util.Glob; - -public class IgnoreCoreClasses implements Predicate { - - private final Predicate impl; - private final Collection filtered = Arrays.asList("java.*", "sun.*", - "javax.*", "org.junit.*", - "junit.*", "org.mockito.*", - "org.powermock.*", - "org.jmock.*", "com.sun.*"); - - IgnoreCoreClasses() { - this.impl = Prelude.not(Prelude.or(Glob.toGlobPredicates(this.filtered))); - } - - @Override - public boolean test(final DependencyAccess a) { - final String owner = a.getDest().getOwner().replace("/", "."); - return this.impl.test(owner); - } - -} diff --git a/pitest/src/main/java/org/pitest/junit/CompoundTestUnitFinder.java b/pitest/src/main/java/org/pitest/junit/CompoundTestUnitFinder.java index 762ea0e91..6e10ef516 100644 --- a/pitest/src/main/java/org/pitest/junit/CompoundTestUnitFinder.java +++ b/pitest/src/main/java/org/pitest/junit/CompoundTestUnitFinder.java @@ -4,6 +4,7 @@ import java.util.List; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.TestUnitFinder; public class CompoundTestUnitFinder implements TestUnitFinder { @@ -15,9 +16,9 @@ public CompoundTestUnitFinder(final List tufs) { } @Override - public List findTestUnits(final Class clazz) { + public List findTestUnits(final Class clazz, TestUnitExecutionListener listener) { for (final TestUnitFinder each : this.tufs) { - final List tus = each.findTestUnits(clazz); + final List tus = each.findTestUnits(clazz, listener); if (!tus.isEmpty()) { return tus; } diff --git a/pitest/src/main/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinder.java b/pitest/src/main/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinder.java index 8d403dcbd..dd04af72c 100644 --- a/pitest/src/main/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinder.java +++ b/pitest/src/main/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinder.java @@ -43,6 +43,7 @@ import org.pitest.reflection.Reflection; import org.pitest.testapi.TestGroupConfig; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.TestUnitFinder; import org.pitest.util.IsolationUtils; @@ -65,7 +66,7 @@ public class JUnitCustomRunnerTestUnitFinder implements TestUnitFinder { } @Override - public List findTestUnits(final Class clazz) { + public List findTestUnits(final Class clazz, TestUnitExecutionListener unused) { final Runner runner = AdaptedJUnitTestUnit.createRunner(clazz); diff --git a/pitest/src/main/java/org/pitest/junit/NullConfiguration.java b/pitest/src/main/java/org/pitest/junit/NullConfiguration.java index 0f0128b26..d8ecee045 100644 --- a/pitest/src/main/java/org/pitest/junit/NullConfiguration.java +++ b/pitest/src/main/java/org/pitest/junit/NullConfiguration.java @@ -11,7 +11,7 @@ public class NullConfiguration implements Configuration { @Override public TestUnitFinder testUnitFinder() { - return c -> Collections.emptyList(); + return (c,l) -> Collections.emptyList(); } @Override diff --git a/pitest/src/main/java/org/pitest/junit/ParameterisedJUnitTestFinder.java b/pitest/src/main/java/org/pitest/junit/ParameterisedJUnitTestFinder.java index 77353353e..1136216b4 100644 --- a/pitest/src/main/java/org/pitest/junit/ParameterisedJUnitTestFinder.java +++ b/pitest/src/main/java/org/pitest/junit/ParameterisedJUnitTestFinder.java @@ -27,11 +27,12 @@ import java.util.Optional; import org.pitest.junit.adapter.AdaptedJUnitTestUnit; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.TestUnitFinder; public class ParameterisedJUnitTestFinder implements TestUnitFinder { @Override - public List findTestUnits(final Class clazz) { + public List findTestUnits(final Class clazz, TestUnitExecutionListener unused) { final Runner runner = AdaptedJUnitTestUnit.createRunner(clazz); if ((runner == null) diff --git a/pitest/src/main/java/org/pitest/mutationtest/config/PrioritisingTestUnitFinder.java b/pitest/src/main/java/org/pitest/mutationtest/config/PrioritisingTestUnitFinder.java index ff966204b..7fee7c64d 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/config/PrioritisingTestUnitFinder.java +++ b/pitest/src/main/java/org/pitest/mutationtest/config/PrioritisingTestUnitFinder.java @@ -1,6 +1,7 @@ package org.pitest.mutationtest.config; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.TestUnitFinder; import java.util.Collections; @@ -14,9 +15,9 @@ class PrioritisingTestUnitFinder implements TestUnitFinder { } @Override - public List findTestUnits(Class clazz) { + public List findTestUnits(Class clazz, TestUnitExecutionListener listener) { for (TestUnitFinder each : orderedChildren) { - List found = each.findTestUnits(clazz); + List found = each.findTestUnits(clazz, listener); if (!found.isEmpty()) { return found; } diff --git a/pitest/src/main/java/org/pitest/testapi/ExecutedInDiscovery.java b/pitest/src/main/java/org/pitest/testapi/ExecutedInDiscovery.java new file mode 100644 index 000000000..e4b145e20 --- /dev/null +++ b/pitest/src/main/java/org/pitest/testapi/ExecutedInDiscovery.java @@ -0,0 +1,9 @@ +package org.pitest.testapi; + +/** + * Marker interface for TestUnits that are implicitly executed + * during discovery. Marker allows them to be excluded from + * re-execution. + */ +public interface ExecutedInDiscovery { +} diff --git a/pitest/src/main/java/org/pitest/testapi/NullExecutionListener.java b/pitest/src/main/java/org/pitest/testapi/NullExecutionListener.java new file mode 100644 index 000000000..0d97f74c0 --- /dev/null +++ b/pitest/src/main/java/org/pitest/testapi/NullExecutionListener.java @@ -0,0 +1,13 @@ +package org.pitest.testapi; + +public class NullExecutionListener implements TestUnitExecutionListener { + @Override + public void executionStarted(Description description) { + // noop + } + + @Override + public void executionFinished(Description description, boolean passed) { + //noop + } +} diff --git a/pitest/src/main/java/org/pitest/testapi/TestUnitExecutionListener.java b/pitest/src/main/java/org/pitest/testapi/TestUnitExecutionListener.java new file mode 100644 index 000000000..1853a7f8a --- /dev/null +++ b/pitest/src/main/java/org/pitest/testapi/TestUnitExecutionListener.java @@ -0,0 +1,11 @@ +package org.pitest.testapi; + +/** + * JUnit 3 and 4 had a clear separation between discovering and executing tests. This + * is no longer the case for JUnit 5. To support both models without double executing + * junit5 tests, this interface is used to listen for execution during discovery. + */ +public interface TestUnitExecutionListener { + void executionStarted(Description description); + void executionFinished(Description description, boolean passed); +} diff --git a/pitest/src/main/java/org/pitest/testapi/TestUnitFinder.java b/pitest/src/main/java/org/pitest/testapi/TestUnitFinder.java index 31071bdc3..cb43423fb 100644 --- a/pitest/src/main/java/org/pitest/testapi/TestUnitFinder.java +++ b/pitest/src/main/java/org/pitest/testapi/TestUnitFinder.java @@ -19,6 +19,11 @@ public interface TestUnitFinder { - List findTestUnits(Class clazz); + /** + * Discover test units for a class. Most implementations can ignore the listener + * parameter, it is only required if tests are executed as part of discovery + * (eg JUnit 5). + */ + List findTestUnits(Class clazz, TestUnitExecutionListener listener); } diff --git a/pitest/src/main/java/org/pitest/testapi/execute/FindTestUnits.java b/pitest/src/main/java/org/pitest/testapi/execute/FindTestUnits.java index 7c6ecc979..6e532ff91 100644 --- a/pitest/src/main/java/org/pitest/testapi/execute/FindTestUnits.java +++ b/pitest/src/main/java/org/pitest/testapi/execute/FindTestUnits.java @@ -7,7 +7,9 @@ import java.util.Set; import org.pitest.testapi.Configuration; +import org.pitest.testapi.NullExecutionListener; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; /** * Scans classes to discover TestUnits @@ -16,13 +18,18 @@ public class FindTestUnits { private final Configuration config; + private final TestUnitExecutionListener listener; - public FindTestUnits(final Configuration config) { + public FindTestUnits(Configuration config) { + this(config, new NullExecutionListener()); + } + + public FindTestUnits(Configuration config, TestUnitExecutionListener listener) { this.config = config; + this.listener = listener; } - public List findTestUnitsForAllSuppliedClasses( - final Iterable> classes) { + public List findTestUnitsForAllSuppliedClasses(Iterable> classes) { final List testUnits = new ArrayList<>(); for (final Class c : classes) { @@ -54,7 +61,7 @@ private void findTestUnits(final List tus, } final List testsInThisClass = this.config.testUnitFinder() - .findTestUnits(suiteClass); + .findTestUnits(suiteClass, listener); if (!testsInThisClass.isEmpty()) { tus.addAll(testsInThisClass); } diff --git a/pitest/src/test/java/org/pitest/TestJUnitConfiguration.java b/pitest/src/test/java/org/pitest/TestJUnitConfiguration.java index a1d3ac758..dcc34a969 100644 --- a/pitest/src/test/java/org/pitest/TestJUnitConfiguration.java +++ b/pitest/src/test/java/org/pitest/TestJUnitConfiguration.java @@ -54,8 +54,8 @@ public class TestJUnitConfiguration { private JUnitCompatibleConfiguration testee = new JUnitCompatibleConfiguration( new TestGroupConfig(), - Collections.emptyList(), - Collections.emptyList()); + Collections.emptyList(), + Collections.emptyList()); private Pitest pitest; private Container container; @@ -630,7 +630,7 @@ private void exclude(Class class1) { final List include = Collections.emptyList(); this.testee = new JUnitCompatibleConfiguration( new TestGroupConfig(include,exclude), - Collections.emptyList(), Collections.emptyList()); + Collections.emptyList(), Collections.emptyList()); } private void run(final Class clazz) { @@ -640,7 +640,7 @@ private void run(final Class clazz) { private List find(Class clazz) { final FindTestUnits finder = new FindTestUnits(this.testee); return finder.findTestUnitsForAllSuppliedClasses(Arrays - .> asList(clazz)); + .asList(clazz)); } } diff --git a/pitest/src/test/java/org/pitest/coverage/execute/CoverageOptionsTest.java b/pitest/src/test/java/org/pitest/coverage/execute/CoverageOptionsTest.java index 0c994d5f0..9f4c1a010 100644 --- a/pitest/src/test/java/org/pitest/coverage/execute/CoverageOptionsTest.java +++ b/pitest/src/test/java/org/pitest/coverage/execute/CoverageOptionsTest.java @@ -12,18 +12,18 @@ public class CoverageOptionsTest { TestPluginArguments pitConfig = TestPluginArguments.defaults(); - CoverageOptions testee = new CoverageOptions(Collections.singletonList("*"), Collections.emptyList(), this.pitConfig, DEFAULT, 0); + CoverageOptions testee = new CoverageOptions(Collections.singletonList("*"), Collections.emptyList(), this.pitConfig, DEFAULT); @Test public void shouldIncludeTargettedClasses() { - this.testee = new CoverageOptions(Collections.singletonList("com.example.*"), Collections.emptyList(), this.pitConfig, DEFAULT, 0); + this.testee = new CoverageOptions(Collections.singletonList("com.example.*"), Collections.emptyList(), this.pitConfig, DEFAULT); assertThat(this.testee.getFilter().test("com.example.Foo")).isTrue(); } @Test public void shouldExcludeExcludedClasses() { - this.testee = new CoverageOptions(Collections.singletonList("com.example.*"), Collections.singletonList("com.example.NotMe"), this.pitConfig, DEFAULT, 0); + this.testee = new CoverageOptions(Collections.singletonList("com.example.*"), Collections.singletonList("com.example.NotMe"), this.pitConfig, DEFAULT); assertThat(this.testee.getFilter().test("com.example.Foo")).isTrue(); assertThat(this.testee.getFilter().test("com.example.NotMe")).isFalse(); diff --git a/pitest/src/test/java/org/pitest/coverage/execute/DependencyFilterTest.java b/pitest/src/test/java/org/pitest/coverage/execute/DependencyFilterTest.java deleted file mode 100644 index a93f8da51..000000000 --- a/pitest/src/test/java/org/pitest/coverage/execute/DependencyFilterTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.pitest.coverage.execute; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.function.Predicate; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.pitest.dependency.DependencyExtractor; -import org.pitest.testapi.Description; -import org.pitest.testapi.ResultCollector; -import org.pitest.testapi.TestUnit; - -public class DependencyFilterTest { - - private DependencyFilter testee; - - @Mock - private DependencyExtractor extractor; - - private TestUnit aTestUnit; - - private TestUnit anotherTestUnit; - - private List tus; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - - this.aTestUnit = makeTestUnit(new Description("foo", String.class)); - this.anotherTestUnit = makeTestUnit(new Description("bar", Integer.class)); - - this.testee = new DependencyFilter(this.extractor, s -> true); - this.tus = Arrays.asList(this.aTestUnit, this.anotherTestUnit); - } - - @Test - public void shouldNotPerformAnalysisWhenDependencyDistanceIsLessThan0() - throws IOException { - when(this.extractor.getMaxDistance()).thenReturn(-1); - final List actual = this.testee - .filterTestsByDependencyAnalysis(this.tus); - assertSame(this.tus, actual); - verify(this.extractor, never()).extractCallDependenciesForPackages( - anyString(), any(Predicate.class)); - } - - @Test - public void shouldReturnOnlyTestUnitsForClassesWithinReach() - throws IOException { - when( - this.extractor.extractCallDependenciesForPackages( - eq(this.aTestUnit.getDescription().getFirstTestClass()), - any(Predicate.class))).thenReturn(Arrays.asList("foo")); - when( - this.extractor.extractCallDependenciesForPackages( - eq(this.anotherTestUnit.getDescription().getFirstTestClass()), - any(Predicate.class))).thenReturn(Collections. emptyList()); - - assertEquals(Arrays.asList(this.aTestUnit), - this.testee.filterTestsByDependencyAnalysis(this.tus)); - - } - - @Test - public void shouldNotRecalculateDependenciesForAlreadyAnalysedClasses() - throws IOException { - - when( - this.extractor.extractCallDependenciesForPackages(eq(this.aTestUnit - .getDescription().getFirstTestClass()), any(Predicate.class))) - .thenReturn(Arrays.asList("foo")); - - this.tus = Arrays.asList(this.aTestUnit, this.aTestUnit); - - this.testee.filterTestsByDependencyAnalysis(this.tus); - verify(this.extractor, times(1)).extractCallDependenciesForPackages( - eq(this.aTestUnit.getDescription().getFirstTestClass()), - any(Predicate.class)); - } - - private TestUnit makeTestUnit(final Description d) { - return new TestUnit() { - - @Override - public void execute(final ResultCollector rc) { - - } - - @Override - public Description getDescription() { - return d; - } - - }; - } -} diff --git a/pitest/src/test/java/org/pitest/dependency/DependencyAccessTest.java b/pitest/src/test/java/org/pitest/dependency/DependencyAccessTest.java deleted file mode 100644 index 42048fddb..000000000 --- a/pitest/src/test/java/org/pitest/dependency/DependencyAccessTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.pitest.dependency; - -import org.junit.Test; - -import nl.jqno.equalsverifier.EqualsVerifier; - -public class DependencyAccessTest { - - @Test - public void shouldObeyHashcodeEqualsContract() { - EqualsVerifier.forClass(DependencyAccess.class).verify(); - } - -} diff --git a/pitest/src/test/java/org/pitest/dependency/DependencyClassVisitorTest.java b/pitest/src/test/java/org/pitest/dependency/DependencyClassVisitorTest.java deleted file mode 100644 index 5d22f64f4..000000000 --- a/pitest/src/test/java/org/pitest/dependency/DependencyClassVisitorTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2010 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.pitest.classpath.ClassPath; -import org.pitest.dependency.DependencyAccess.Member; -import org.pitest.functional.FCollection; - -public class DependencyClassVisitorTest { - - private DependencyClassVisitor testee; - private final Set gatheredDependencies = new HashSet<>(); - private final Set gatheredAccess = new HashSet<>(); - private final ClassPath cp = new ClassPath(); - - @Before - public void setUp() { - final Consumer se = a -> { - DependencyClassVisitorTest.this.gatheredAccess.add(a); - DependencyClassVisitorTest.this.gatheredDependencies.add(a.getDest() - .getOwner()); - }; - this.testee = new DependencyClassVisitor(new ClassWriter(0), se); - } - - public static class HasDependencyFromCallingNew { - public void foo() { - new Integer(1); - } - } - - @Test - public void shouldRecordDirectDependenciesFromCallingNew() throws Exception { - examineClassWithTestee(HasDependencyFromCallingNew.class); - assertEquals(classesToNames(Integer.class), this.gatheredDependencies); - } - - public enum AnEnum { - value - } - - public static class HasField { - AnEnum field = AnEnum.value; - - } - - @Test - public void shouldRecordDependenciesFromInitializedFields() throws Exception { - examineClassWithTestee(HasField.class); - assertEquals(classesToNames(AnEnum.class, HasField.class), - this.gatheredDependencies); - - } - - public static class MakesMethodCall { - public void foo() { - Arrays.asList(); - } - } - - @Test - public void shouldRecordDependenciesFromMethodCalls() throws Exception { - examineClassWithTestee(MakesMethodCall.class); - assertEquals(classesToNames(Arrays.class), this.gatheredDependencies); - final Member foo = new Member( - classToJvmName().apply(MakesMethodCall.class), "foo"); - assertTrue(this.gatheredAccess.contains(new DependencyAccess(foo, - new Member("java/util/Arrays", "asList")))); - } - - private void examineClassWithTestee(final Class clazz) throws IOException { - final byte[] bytes = this.cp.getClassData(clazz.getName()); - final ClassReader reader = new ClassReader(bytes); - reader.accept(this.testee, 0); - } - - private Set classesToNames(final Class... classes) { - final Set set = new HashSet<>(); - FCollection.mapTo(Arrays.asList(classes), classToJvmName(), set); - return set; - } - - private Function, String> classToJvmName() { - return a -> a.getName().replace(".", "/"); - } - -} diff --git a/pitest/src/test/java/org/pitest/dependency/DependencyExtractorTest.java b/pitest/src/test/java/org/pitest/dependency/DependencyExtractorTest.java deleted file mode 100644 index 69821a028..000000000 --- a/pitest/src/test/java/org/pitest/dependency/DependencyExtractorTest.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2010 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -import org.junit.Test; -import org.pitest.classpath.ClassPathByteArraySource; - -public class DependencyExtractorTest { - - private DependencyExtractor testee; - - public static class Foo { - public void one() { - new Bar(); - } - - public void two() { - new Car(); - } - } - - public static class Bar { - Far f = new Far(); - } - - public static class Car { - - } - - public static class Far { - VeryFar f = new VeryFar(); - } - - public static class VeryFar { - - } - - public static class CyclicFoo { - CyclicBar b = new CyclicBar(); - } - - public static class CyclicBar { - CyclicFoo f = new CyclicFoo(); - } - - @Test - public void shouldFindOnlyImmediateDependenciesWhenDepthIsOne() - throws Exception { - constructWithDepthOf(1); - final Collection actual = this.testee - .extractCallDependenciesForPackages(Foo.class.getName(), - s -> true); - final Set expected = asSet(classToJvmName(Bar.class), - classToJvmName(Car.class)); - assertCollectionEquals(expected, actual); - } - - @Test - public void shouldTraverseTwoLevelsOfDependenciesWhenDepthIsTwo() - throws Exception { - constructWithDepthOf(2); - final Collection actual = this.testee - .extractCallDependenciesForPackages(Foo.class.getName(), - s -> true); - final Set expected = asSet(classToJvmName(Bar.class), - classToJvmName(Car.class), classToJvmName(Far.class)); - assertCollectionEquals(expected, actual); - } - - @Test - public void shouldTraverseUnboundedWhenDepthIsZero() throws Exception { - constructWithDepthOf(0); - final Collection actual = this.testee - .extractCallDependenciesForPackages(Foo.class.getName(), - s -> true); - final List expected = Arrays.asList(classToJvmName(Bar.class), - classToJvmName(Car.class), classToJvmName(Far.class), - classToJvmName(VeryFar.class)); - assertCollectionEquals(expected, actual); - } - - @Test - public void shouldNotPickUpDependenciesFromFilteredMethods() throws Exception { - constructWithDepthOf(0); - final Collection actual = this.testee.extractCallDependencies( - Foo.class.getName(), excludeMethodsCalledOne()); - final Set expected = asSet(classToJvmName(Car.class)); - assertCollectionEquals(expected, actual); - } - - @Test - public void shouldFindDependenciesReachedViaClassesNotMatchingFilter() - throws IOException { - constructWithDepthOf(5); - final Collection actual = this.testee - .extractCallDependenciesForPackages(Foo.class.getName(), - includeOnlyThingsCalled("VeryFar"), ignoreCoreClasses()); - final Set expected = asSet(classToJvmName(VeryFar.class)); - assertCollectionEquals(expected, actual); - } - - @Test - public void shouldHandleCyclicDependencies() throws Exception { - constructWithDepthOf(0); - final Collection actual = this.testee - .extractCallDependenciesForPackages(CyclicFoo.class.getName(), - s -> true); - final List expected = Arrays - .asList(classToJvmName(CyclicBar.class)); - assertCollectionEquals(expected, actual); - } - - private Predicate ignoreCoreClasses() { - return a -> !a.getDest().getOwner().startsWith("java"); - - } - - private Predicate includeOnlyThingsCalled(final String subString) { - return a -> a.contains(subString); - } - - private void constructWithDepthOf(final int depth) { - this.testee = new DependencyExtractor(new ClassPathByteArraySource(), depth); - - } - - private Predicate excludeMethodsCalledOne() { - return a -> !a.getSource().getName().equals("one"); - } - - private void assertCollectionEquals(final Collection expected, - final Collection actual) { - final Set expectedSet = new HashSet<>(); - expectedSet.addAll(expected); - - final Set actualSet = new HashSet<>(); - actualSet.addAll(actual); - - assertEquals(expectedSet, actualSet); - - } - - private Set asSet(final String... values) { - final Set set = new HashSet<>(); - set.addAll(Arrays.asList(values)); - return set; - } - - private String classToJvmName(final Class clazz) { - - return clazz.getName().replace(".", "/"); - - } -} diff --git a/pitest/src/test/java/org/pitest/dependency/IgnoreCoreClassesTest.java b/pitest/src/test/java/org/pitest/dependency/IgnoreCoreClassesTest.java deleted file mode 100644 index 19043f3f1..000000000 --- a/pitest/src/test/java/org/pitest/dependency/IgnoreCoreClassesTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2011 Henry Coles - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and limitations under the License. - */ -package org.pitest.dependency; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import javax.net.SocketFactory; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runners.JUnit4; -import org.mockito.Mockito; -import org.pitest.dependency.DependencyAccess.Member; -import org.pitest.dependency.DependencyExtractorTest.Foo; - -public class IgnoreCoreClassesTest { - - private IgnoreCoreClasses testee; - - @Before - public void setUp() { - this.testee = new IgnoreCoreClasses(); - } - - @Test - public void shouldIgnoreJavaLangClasses() { - assertIgnored(Integer.class); - } - - @SuppressWarnings("deprecation") - @Test - public void shouldIgnoreLegacyJUnitClasses() { - assertIgnored(junit.framework.Assert.class); - } - - @Test - public void shouldIgnoreJUnitClasses() { - assertIgnored(JUnit4.class); - } - - @Test - public void shouldIgnoreMockito() { - assertIgnored(Mockito.class); - } - - @Test - public void shouldIgnorePowerMock() { - assertIgnored("org.powermock.PowerMockIgnore"); - } - - private void assertIgnored(final String clazz) { - assertFalse(this.testee.test(makeAccessFor(clazz))); - } - - private void assertIgnored(final Class clazz) { - assertIgnored(clazz.getName()); - } - - @Test - public void shouldIgnoreJavaX() { - assertFalse(this.testee.test(makeAccessFor(SocketFactory.class))); - } - - @Test - public void shouldNotIgnoreOtherPackages() { - assertTrue(this.testee.test(makeAccessFor(Foo.class))); - } - - private DependencyAccess makeAccessFor(final Class clazz) { - return makeAccessFor(clazz.getName()); - } - - private DependencyAccess makeAccessFor(final String clazz) { - return new DependencyAccess(new Member("foo", "()V"), new Member(clazz, - "()V")); - } - -} diff --git a/pitest/src/test/java/org/pitest/executingtest/ExecutingTest.java b/pitest/src/test/java/org/pitest/executingtest/ExecutingTest.java new file mode 100644 index 000000000..935dfe717 --- /dev/null +++ b/pitest/src/test/java/org/pitest/executingtest/ExecutingTest.java @@ -0,0 +1,8 @@ +package org.pitest.executingtest; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ExecutingTest { +} \ No newline at end of file diff --git a/pitest/src/test/java/org/pitest/executingtest/ExecutingTestFinder.java b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestFinder.java new file mode 100644 index 000000000..aa0cd6557 --- /dev/null +++ b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestFinder.java @@ -0,0 +1,84 @@ +package org.pitest.executingtest; + +import org.pitest.simpletest.NoArgsConstructorInstantiationStrategy; +import org.pitest.simpletest.TestMethod; +import org.pitest.simpletest.TestStep; +import org.pitest.simpletest.steps.CallStep; +import org.pitest.simpletest.steps.NoArgsInstantiateStep; +import org.pitest.testapi.Description; +import org.pitest.testapi.TestListener; +import org.pitest.testapi.TestResult; +import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; +import org.pitest.testapi.TestUnitFinder; +import org.pitest.testapi.execute.Pitest; +import org.pitest.testapi.execute.containers.UnContainer; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; + +/** + * Toy example of a finder that executes tests during discovery. For testing + * purposes only. + */ +public class ExecutingTestFinder implements TestUnitFinder { + @Override + public List findTestUnits(Class clazz, TestUnitExecutionListener listener) { + return Arrays.stream(clazz.getMethods()) + .filter(m -> m.getAnnotation(ExecutingTest.class) != null) + .map(m -> toTest(clazz, m)) + .map(m -> execute(listener, m)) + .collect(Collectors.toList()); + + } + + private TestUnit toTest(Class clazz, Method m) { + TestMethod testMethod = new TestMethod(m); + List steps = asList(NoArgsInstantiateStep.instantiate(clazz), new CallStep(testMethod)); + return new ExecutingTestUnit(new Description(testMethod.getName(), clazz), steps); + } + + private TestUnit execute(TestUnitExecutionListener listener, TestUnit testUnit) { + new Pitest(convertListener(listener)).run(new UnContainer(), Collections.singletonList(testUnit)); + return testUnit; + } + + private TestListener convertListener(TestUnitExecutionListener listener) { + return new TestListener() { + @Override + public void onRunStart() { + + } + + @Override + public void onTestStart(Description d) { + listener.executionStarted(d); + } + + @Override + public void onTestFailure(TestResult tr) { + listener.executionFinished(tr.getDescription(), false); + } + + @Override + public void onTestSkipped(TestResult tr) { + + } + + @Override + public void onTestSuccess(TestResult tr) { + listener.executionFinished(tr.getDescription(), true); + } + + @Override + public void onRunEnd() { + + } + }; + } +} diff --git a/pitest/src/test/java/org/pitest/executingtest/ExecutingTestPlugin.java b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestPlugin.java new file mode 100644 index 000000000..096fbed94 --- /dev/null +++ b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestPlugin.java @@ -0,0 +1,34 @@ +package org.pitest.executingtest; + +import org.pitest.classinfo.ClassByteArraySource; +import org.pitest.testapi.Configuration; +import org.pitest.testapi.TestGroupConfig; +import org.pitest.testapi.TestPluginFactory; + +import java.util.Collection; + +/** + * Toy test plugin that executes tests during discovery in the same + * manner as JUnit 5. Exists purely to allow integration testing. + */ +public class ExecutingTestPlugin implements TestPluginFactory { + + @Override + public String description() { + return "Executing test plugin for testing"; + } + + @Override + public Configuration createTestFrameworkConfiguration(TestGroupConfig config, + ClassByteArraySource source, + Collection excludedRunners, + Collection includedMethods) { + return new TestExecutingConfiguration(); + } + + @Override + public String name() { + return "ExecutingPluginForTesting"; + } + +} \ No newline at end of file diff --git a/pitest/src/test/java/org/pitest/executingtest/ExecutingTestUnit.java b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestUnit.java new file mode 100644 index 000000000..92107092d --- /dev/null +++ b/pitest/src/test/java/org/pitest/executingtest/ExecutingTestUnit.java @@ -0,0 +1,16 @@ +package org.pitest.executingtest; + +import org.pitest.simpletest.SteppedTestUnit; +import org.pitest.simpletest.TestStep; +import org.pitest.testapi.Description; +import org.pitest.testapi.ExecutedInDiscovery; + +import java.util.Collection; +import java.util.Optional; + +public class ExecutingTestUnit extends SteppedTestUnit implements ExecutedInDiscovery { + public ExecutingTestUnit(Description description, Collection steps) { + super(description, steps, Optional.empty()); + } + +} diff --git a/pitest/src/test/java/org/pitest/executingtest/TestExecutingConfiguration.java b/pitest/src/test/java/org/pitest/executingtest/TestExecutingConfiguration.java new file mode 100644 index 000000000..9f0612c76 --- /dev/null +++ b/pitest/src/test/java/org/pitest/executingtest/TestExecutingConfiguration.java @@ -0,0 +1,28 @@ +package org.pitest.executingtest; + +import org.pitest.extension.common.NoTestSuiteFinder; +import org.pitest.help.PitHelpError; +import org.pitest.testapi.Configuration; +import org.pitest.testapi.TestSuiteFinder; +import org.pitest.testapi.TestUnitFinder; + +import java.util.Optional; + +public class TestExecutingConfiguration implements Configuration { + + @Override + public TestUnitFinder testUnitFinder() { + return new ExecutingTestFinder(); + } + + @Override + public TestSuiteFinder testSuiteFinder() { + return new NoTestSuiteFinder(); + } + + @Override + public Optional verifyEnvironment() { + return Optional.empty(); + } + +} diff --git a/pitest/src/test/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinderTest.java b/pitest/src/test/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinderTest.java index 0b8f371a7..13b89d7f6 100644 --- a/pitest/src/test/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinderTest.java +++ b/pitest/src/test/java/org/pitest/junit/JUnitCustomRunnerTestUnitFinderTest.java @@ -47,6 +47,7 @@ import org.junit.runners.model.RunnerBuilder; import org.mockito.MockitoAnnotations; import org.pitest.junit.RunnerSuiteFinderTest.ThrowsOnDiscoverySuite; +import org.pitest.testapi.NullExecutionListener; import org.pitest.testapi.TestGroupConfig; import org.pitest.testapi.TestUnit; @@ -177,7 +178,7 @@ public void shouldNotFindTestsInNestedCustomSuites() { } private Collection findWithTestee(final Class clazz) { - return this.testee.findTestUnits(clazz); + return this.testee.findTestUnits(clazz, new NullExecutionListener()); } public static class NotATest { @@ -199,7 +200,7 @@ public void testExample() { @Test public void shouldFindTestUnitsInCustomJUnit3Class() { final Collection actual = this.testee - .findTestUnits(JMockTest.class); + .findTestUnits(JMockTest.class, new NullExecutionListener()); assertFalse(actual.isEmpty()); } diff --git a/pitest/src/test/java/org/pitest/junit/NullConfigurationTest.java b/pitest/src/test/java/org/pitest/junit/NullConfigurationTest.java index 8d2fdc621..4a28472a2 100644 --- a/pitest/src/test/java/org/pitest/junit/NullConfigurationTest.java +++ b/pitest/src/test/java/org/pitest/junit/NullConfigurationTest.java @@ -1,6 +1,7 @@ package org.pitest.junit; import org.junit.Test; +import org.pitest.testapi.NullExecutionListener; import static org.assertj.core.api.Assertions.assertThat; @@ -10,7 +11,7 @@ public class NullConfigurationTest { @Test public void findsNoTests() { - assertThat(underTest.testUnitFinder().findTestUnits(this.getClass())).isEmpty(); + assertThat(underTest.testUnitFinder().findTestUnits(this.getClass(), new NullExecutionListener())).isEmpty(); } @Test diff --git a/pitest/src/test/java/org/pitest/junit/ParameterisedJUnitTestFinderTest.java b/pitest/src/test/java/org/pitest/junit/ParameterisedJUnitTestFinderTest.java index fdbcf5c78..3a9995fb5 100644 --- a/pitest/src/test/java/org/pitest/junit/ParameterisedJUnitTestFinderTest.java +++ b/pitest/src/test/java/org/pitest/junit/ParameterisedJUnitTestFinderTest.java @@ -25,6 +25,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import org.pitest.testapi.NullExecutionListener; import org.pitest.testapi.TestUnit; public class ParameterisedJUnitTestFinderTest { @@ -72,7 +73,7 @@ public void shouldReturnNoTestForNonParameterisedTest() { } private Collection findWithTestee(final Class clazz) { - return this.testee.findTestUnits(clazz); + return this.testee.findTestUnits(clazz, new NullExecutionListener()); } } diff --git a/pitest/src/test/java/org/pitest/mutationtest/config/PrioritisingTestConfigurationTest.java b/pitest/src/test/java/org/pitest/mutationtest/config/PrioritisingTestConfigurationTest.java index f1ae8a519..917af4d1e 100644 --- a/pitest/src/test/java/org/pitest/mutationtest/config/PrioritisingTestConfigurationTest.java +++ b/pitest/src/test/java/org/pitest/mutationtest/config/PrioritisingTestConfigurationTest.java @@ -5,6 +5,7 @@ import org.pitest.help.PitHelpError; import org.pitest.testapi.Configuration; import org.pitest.testapi.Description; +import org.pitest.testapi.NullExecutionListener; import org.pitest.testapi.ResultCollector; import org.pitest.testapi.TestSuiteFinder; import org.pitest.testapi.TestUnit; @@ -28,7 +29,7 @@ public class PrioritisingTestConfigurationTest { public void findsNoTestsWhenNothingMatchesChildConfiguration() { Configuration findsNothing = configuration(1, emptyList()); PrioritisingTestConfiguration testee = new PrioritisingTestConfiguration(asList(findsNothing)); - List actual = testee.testUnitFinder().findTestUnits(String.class); + List actual = testee.testUnitFinder().findTestUnits(String.class, new NullExecutionListener()); assertThat(actual).isEmpty(); } @@ -39,7 +40,7 @@ public void highestPriorityConfigurationFindsTest() { Configuration c2 = configuration(2, dontFindMe); PrioritisingTestConfiguration testee = new PrioritisingTestConfiguration(asList(c0, c1, c2)); - List actual = testee.testUnitFinder().findTestUnits(String.class); + List actual = testee.testUnitFinder().findTestUnits(String.class, new NullExecutionListener()); assertThat(actual).containsOnly(findMe); } @@ -50,7 +51,7 @@ public void configurationsWithEnvironmentalErrorsNotUsed() { Configuration c1 = configuration(2, findMe); PrioritisingTestConfiguration testee = new PrioritisingTestConfiguration(asList(c0, c1)); - List actual = testee.testUnitFinder().findTestUnits(String.class); + List actual = testee.testUnitFinder().findTestUnits(String.class, new NullExecutionListener()); assertThat(actual).containsOnly(findMe); } @@ -62,7 +63,7 @@ public void allowsMixedTestTypes() { Configuration c2 = configuration(3, dontFindMe); PrioritisingTestConfiguration testee = new PrioritisingTestConfiguration(asList(findsNothing, c1, c2)); - List actual = testee.testUnitFinder().findTestUnits(String.class); + List actual = testee.testUnitFinder().findTestUnits(String.class, new NullExecutionListener()); assertThat(actual).containsOnly(findMe); } @@ -130,7 +131,7 @@ public int priority() { @Override public TestUnitFinder testUnitFinder() { - return c -> testUnits; + return (c,l) -> testUnits; } @Override @@ -155,7 +156,7 @@ public int priority() { @Override public TestUnitFinder testUnitFinder() { - return c -> emptyList(); + return (c,l) -> emptyList(); } @Override diff --git a/pitest/src/test/java/org/pitest/simpletest/BasicTestUnitFinder.java b/pitest/src/test/java/org/pitest/simpletest/BasicTestUnitFinder.java index 093b55fd9..2454efc55 100644 --- a/pitest/src/test/java/org/pitest/simpletest/BasicTestUnitFinder.java +++ b/pitest/src/test/java/org/pitest/simpletest/BasicTestUnitFinder.java @@ -32,6 +32,7 @@ import org.pitest.simpletest.steps.CallStep; import org.pitest.testapi.Description; import org.pitest.testapi.TestUnit; +import org.pitest.testapi.TestUnitExecutionListener; import org.pitest.testapi.TestUnitFinder; import org.pitest.util.PitError; @@ -48,7 +49,7 @@ public BasicTestUnitFinder( } @Override - public List findTestUnits(final Class testClass) { + public List findTestUnits(final Class testClass, TestUnitExecutionListener unused) { try { final List units = new ArrayList<>(); diff --git a/pitest/src/test/java/org/pitest/simpletest/InstantiationStrategy.java b/pitest/src/test/java/org/pitest/simpletest/InstantiationStrategy.java index bdd47c45e..c77b2f01d 100644 --- a/pitest/src/test/java/org/pitest/simpletest/InstantiationStrategy.java +++ b/pitest/src/test/java/org/pitest/simpletest/InstantiationStrategy.java @@ -19,8 +19,8 @@ public interface InstantiationStrategy { - public boolean canInstantiate(Class clazz); + boolean canInstantiate(Class clazz); - public List instantiations(Class clazz); + List instantiations(Class clazz); } diff --git a/pitest/src/test/resources/META-INF/services/org.pitest.testapi.TestPluginFactory b/pitest/src/test/resources/META-INF/services/org.pitest.testapi.TestPluginFactory index a30029d77..c23656f01 100644 --- a/pitest/src/test/resources/META-INF/services/org.pitest.testapi.TestPluginFactory +++ b/pitest/src/test/resources/META-INF/services/org.pitest.testapi.TestPluginFactory @@ -1 +1,2 @@ -org.pitest.simpletest.SimpleTestPlugin \ No newline at end of file +org.pitest.simpletest.SimpleTestPlugin +org.pitest.executingtest.ExecutingTestPlugin \ No newline at end of file