From 5d0c28000563a5ec08251971042efc22d9b4c54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 12 Aug 2021 16:56:13 +0200 Subject: [PATCH 1/3] Classloader test detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Silva --- .../spoonlabs/flacoco/api/Suspiciousness.java | 2 +- .../fr/spoonlabs/flacoco/cli/FlacocoMain.java | 4 + .../flacoco/core/config/FlacocoConfig.java | 16 +++ .../coverage/CoverageFromSingleTestUnit.java | 2 +- .../flacoco/core/coverage/CoverageMatrix.java | 2 +- .../flacoco/core/coverage/CoverageRunner.java | 5 +- .../coverage/framework/JUnit4Strategy.java | 24 +++- .../coverage/framework/JUnit5Strategy.java | 24 +++- .../framework/TestFrameworkStrategy.java | 28 ++-- .../flacoco/core/test/SpoonTestMethod.java | 64 --------- .../flacoco/core/test/StringTestMethod.java | 46 ------- .../flacoco/core/test/TestContext.java | 1 + .../flacoco/core/test/TestDetector.java | 60 ++------- .../flacoco/core/test/TestMethod.java | 14 -- .../core/test/method/SpoonTestMethod.java | 64 +++++++++ .../core/test/method/StringTestMethod.java | 46 +++++++ .../flacoco/core/test/method/TestMethod.java | 14 ++ .../strategies/TestDetectionStrategy.java | 11 ++ .../classloader/ClassloaderStrategy.java | 64 +++++++++ .../CustomClassLoaderThreadFactory.java | 25 ++++ .../classloader/finder/Processor.java | 117 +++++++++++++++++ .../classloader/finder/TestFinderRunner.java | 38 ++++++ .../finder/classes/ClassFinder.java | 7 + .../classes/impl/ClassloaderFinder.java | 28 ++++ .../classes/impl/SourceFolderFinder.java | 46 +++++++ .../finder/filters/TestMethodFilter.java | 121 ++++++++++++++++++ .../classloader/finder/filters/TestType.java | 7 + .../testrunner/TestRunnerStrategy.java | 76 +++++++++++ .../SpectrumSuspiciousComputation.java | 2 +- .../fr/spoonlabs/flacoco/api/FlacocoTest.java | 2 +- .../flacoco/cli/FlacocoMainTest.java | 9 +- .../core/coverage/CoverageRunnerTest.java | 2 +- .../flacoco/core/test/TestDetectorTest.java | 28 +++- .../SpectrumSuspiciousComputationTest.java | 2 +- 34 files changed, 785 insertions(+), 216 deletions(-) delete mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/SpoonTestMethod.java delete mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/StringTestMethod.java delete mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/TestMethod.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/method/SpoonTestMethod.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/method/StringTestMethod.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/method/TestMethod.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/TestDetectionStrategy.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/ClassloaderStrategy.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/CustomClassLoaderThreadFactory.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/TestFinderRunner.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/ClassFinder.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestMethodFilter.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestType.java create mode 100644 src/main/java/fr/spoonlabs/flacoco/core/test/strategies/testrunner/TestRunnerStrategy.java diff --git a/src/main/java/fr/spoonlabs/flacoco/api/Suspiciousness.java b/src/main/java/fr/spoonlabs/flacoco/api/Suspiciousness.java index 03bd3687..937102f1 100644 --- a/src/main/java/fr/spoonlabs/flacoco/api/Suspiciousness.java +++ b/src/main/java/fr/spoonlabs/flacoco/api/Suspiciousness.java @@ -1,6 +1,6 @@ package fr.spoonlabs.flacoco.api; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import java.util.List; diff --git a/src/main/java/fr/spoonlabs/flacoco/cli/FlacocoMain.java b/src/main/java/fr/spoonlabs/flacoco/cli/FlacocoMain.java index 61432d4b..b3c65fcb 100644 --- a/src/main/java/fr/spoonlabs/flacoco/cli/FlacocoMain.java +++ b/src/main/java/fr/spoonlabs/flacoco/cli/FlacocoMain.java @@ -109,6 +109,9 @@ public enum Format { String customExporter; } + @Option(names = {"--testDetectionStrategy"}, description = "Strategy for test detection stage. Defaults to CLASSLOADER. Valid values: ${COMPLETION-CANDIDATES}") + FlacocoConfig.TestDetectionStrategy testDetectionStrategy = FlacocoConfig.TestDetectionStrategy.CLASSLOADER; + @CommandLine.ArgGroup(exclusive = false, multiplicity = "0..1", heading = "Setting any of these options will result in test detection being bypassed.") Tests tests = new Tests(); @@ -182,6 +185,7 @@ private void setupFlacocoConfig() { config.setIncludeZeros(includeZeros); config.setComplianceLevel(complianceLevel); + config.setTestDetectionStrategy(this.testDetectionStrategy); config.setjUnit4Tests(this.tests.jUnit4Tests); config.setjUnit5Tests(this.tests.jUnit5Tests); diff --git a/src/main/java/fr/spoonlabs/flacoco/core/config/FlacocoConfig.java b/src/main/java/fr/spoonlabs/flacoco/core/config/FlacocoConfig.java index c4f9a2cf..0ba5051f 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/config/FlacocoConfig.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/config/FlacocoConfig.java @@ -19,6 +19,11 @@ public enum FaultLocalizationFamily { SPECTRUM_BASED, } + public enum TestDetectionStrategy { + TEST_RUNNER, + CLASSLOADER + } + private static FlacocoConfig instance; private String workspace; @@ -39,6 +44,7 @@ public enum FaultLocalizationFamily { private boolean includeZeros; private int complianceLevel; + private TestDetectionStrategy testDetectionStrategy; private List jUnit4Tests; private List jUnit5Tests; @@ -76,6 +82,7 @@ private void initDefaults() { this.includeZeros = false; this.complianceLevel = 8; + this.testDetectionStrategy = TestDetectionStrategy.CLASSLOADER; this.jUnit4Tests = new ArrayList<>(); this.jUnit5Tests = new ArrayList<>(); @@ -223,6 +230,14 @@ public void setTestRunnerJVMArgs(String testRunnerJVMArgs) { this.testRunnerJVMArgs = testRunnerJVMArgs; } + public TestDetectionStrategy getTestDetectionStrategy() { + return testDetectionStrategy; + } + + public void setTestDetectionStrategy(TestDetectionStrategy testDetectionStrategy) { + this.testDetectionStrategy = testDetectionStrategy; + } + public List getjUnit4Tests() { return jUnit4Tests; } @@ -299,6 +314,7 @@ public String toString() { ", threshold=" + threshold + ", includeZero=" + includeZeros + ", complianceLevel=" + complianceLevel + + ", testDetectionStrategy=" + testDetectionStrategy + ", jUnit4Tests='" + jUnit4Tests + '\'' + ", jUnit5Tests='" + jUnit5Tests + '\'' + ", family=" + family + diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageFromSingleTestUnit.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageFromSingleTestUnit.java index a6353178..d21f541e 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageFromSingleTestUnit.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageFromSingleTestUnit.java @@ -2,7 +2,7 @@ import eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod; import eu.stamp_project.testrunner.listener.impl.CoverageDetailed; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; /** * Contains the results of the execution of a single test case (i.e., a method). diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageMatrix.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageMatrix.java index 87168cd7..3e9f43b5 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageMatrix.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageMatrix.java @@ -5,7 +5,7 @@ import eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod; import eu.stamp_project.testrunner.listener.impl.CoverageDetailed; import eu.stamp_project.testrunner.listener.impl.CoverageFromClass; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Logger; import java.util.*; diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunner.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunner.java index 41173dba..2bd8c766 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunner.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunner.java @@ -1,12 +1,9 @@ package fr.spoonlabs.flacoco.core.coverage; -import ch.scheitlin.alex.java.StackTrace; -import ch.scheitlin.alex.java.StackTraceParser; import eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod; -import eu.stamp_project.testrunner.listener.impl.CoverageDetailed; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.test.TestContext; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Logger; import java.util.List; diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit4Strategy.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit4Strategy.java index 7e95ebe8..7e68edfa 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit4Strategy.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit4Strategy.java @@ -4,25 +4,37 @@ import eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.test.TestContext; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Logger; import java.util.concurrent.TimeoutException; public class JUnit4Strategy extends TestFrameworkStrategy { - private Logger logger = Logger.getLogger(JUnit4Strategy.class); - private FlacocoConfig config = FlacocoConfig.getInstance(); + private static final Logger logger = Logger.getLogger(JUnit4Strategy.class); + + private static JUnit4Strategy instance; + + private JUnit4Strategy() { + + } + + public static JUnit4Strategy getInstance() { + if (instance == null) { + instance = new JUnit4Strategy(); + } + return instance; + } @Override public CoveredTestResultPerTestMethod execute(TestContext testContext) throws TimeoutException { - this.logger.debug("Running " + testContext); + logger.debug("Running " + testContext); this.setupTestRunnerEntryPoint(); return EntryPoint.runCoveredTestResultPerTestMethods( this.computeClasspath(), - config.getBinJavaDir(), - config.getBinTestDir(), + FlacocoConfig.getInstance().getBinJavaDir(), + FlacocoConfig.getInstance().getBinTestDir(), testContext.getTestMethods().stream().map(TestMethod::getFullyQualifiedClassName).distinct().toArray(String[]::new), new String[0] ); diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit5Strategy.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit5Strategy.java index f9c0fcde..9ff88ff2 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit5Strategy.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/JUnit5Strategy.java @@ -4,19 +4,31 @@ import eu.stamp_project.testrunner.listener.CoveredTestResultPerTestMethod; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.test.TestContext; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Logger; import java.util.concurrent.TimeoutException; public class JUnit5Strategy extends TestFrameworkStrategy { - private Logger logger = Logger.getLogger(JUnit5Strategy.class); - private FlacocoConfig config = FlacocoConfig.getInstance(); + private static final Logger logger = Logger.getLogger(JUnit5Strategy.class); + + private static JUnit5Strategy instance; + + private JUnit5Strategy() { + + } + + public static JUnit5Strategy getInstance() { + if (instance == null) { + instance = new JUnit5Strategy(); + } + return instance; + } @Override public CoveredTestResultPerTestMethod execute(TestContext testContext) throws TimeoutException { - this.logger.debug("Running " + testContext); + logger.debug("Running " + testContext); this.setupTestRunnerEntryPoint(); // test-runner needs a flag for JUnit5 tests @@ -24,8 +36,8 @@ public CoveredTestResultPerTestMethod execute(TestContext testContext) throws Ti return EntryPoint.runCoveredTestResultPerTestMethods( this.computeClasspath(), - config.getBinJavaDir(), - config.getBinTestDir(), + FlacocoConfig.getInstance().getBinJavaDir(), + FlacocoConfig.getInstance().getBinTestDir(), testContext.getTestMethods().stream().map(TestMethod::getFullyQualifiedClassName).distinct().toArray(String[]::new), new String[0] ); diff --git a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/TestFrameworkStrategy.java b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/TestFrameworkStrategy.java index d43fe076..4a01cf87 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/TestFrameworkStrategy.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/coverage/framework/TestFrameworkStrategy.java @@ -13,9 +13,7 @@ public abstract class TestFrameworkStrategy { - private Logger logger = Logger.getLogger(TestFrameworkStrategy.class); - private FlacocoConfig config = FlacocoConfig.getInstance(); - + private static final Logger logger = Logger.getLogger(TestFrameworkStrategy.class); public abstract CoveredTestResultPerTestMethod execute(TestContext testContext) throws TimeoutException; @@ -23,13 +21,14 @@ public abstract class TestFrameworkStrategy { * Auxiliary method to setup test-runners default options */ protected void setupTestRunnerEntryPoint() { + FlacocoConfig config = FlacocoConfig.getInstance(); EntryPoint.coverageDetail = ParserOptions.CoverageTransformerDetail.DETAIL_COMPRESSED; - EntryPoint.workingDirectory = new File(this.config.getWorkspace()); - EntryPoint.verbose = this.config.isTestRunnerVerbose(); - EntryPoint.timeoutInMs = this.config.getTestRunnerTimeoutInMs(); - EntryPoint.JVMArgs = this.config.getTestRunnerJVMArgs(); + EntryPoint.workingDirectory = new File(config.getWorkspace()); + EntryPoint.verbose = config.isTestRunnerVerbose(); + EntryPoint.timeoutInMs = config.getTestRunnerTimeoutInMs(); + EntryPoint.JVMArgs = config.getTestRunnerJVMArgs(); EntryPoint.jUnit5Mode = false; - if (this.config.isCoverTests()) { + if (config.isCoverTests()) { throw new UnsupportedOperationException(); } } @@ -40,8 +39,9 @@ protected void setupTestRunnerEntryPoint() { * @return Classpath for test-runner execution */ protected String computeClasspath() { - String classpath = this.config.getClasspath(); - String mavenHome = this.config.getMavenHome(); + FlacocoConfig config = FlacocoConfig.getInstance(); + String classpath = config.getClasspath(); + String mavenHome = config.getMavenHome(); String junitClasspath; String jacocoClassPath; @@ -59,11 +59,11 @@ protected String computeClasspath() { jacocoClassPath = mavenHome + "org/jacoco/org.jacoco.core/0.8.7/org.jacoco.core-0.8.7.jar"; // Add JUnit dependencies - if (this.config.getCustomJUnitClasspath() != null) - junitClasspath = this.config.getCustomJUnitClasspath(); + if (config.getCustomJUnitClasspath() != null) + junitClasspath = config.getCustomJUnitClasspath(); // Add jacoco dependencies - if (this.config.getCustomJacocoClasspath() != null) - jacocoClassPath = this.config.getCustomJacocoClasspath(); + if (config.getCustomJacocoClasspath() != null) + jacocoClassPath = config.getCustomJacocoClasspath(); return junitClasspath + File.pathSeparatorChar + jacocoClassPath + File.pathSeparatorChar diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/SpoonTestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/SpoonTestMethod.java deleted file mode 100644 index 4d544a8d..00000000 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/SpoonTestMethod.java +++ /dev/null @@ -1,64 +0,0 @@ -package fr.spoonlabs.flacoco.core.test; - -import spoon.reflect.declaration.CtMethod; -import spoon.reflect.declaration.CtType; - -import java.util.Objects; - -/** - * Contains all the information about a single test unit in a Spoonful way, - * such as the test class and the method models - * - * @author andre15silva - */ -public class SpoonTestMethod implements TestMethod { - - private CtType testClassModel; - - private String fullyQualifiedClassName; - - private CtMethod testMethodModel; - - private String fullyQualifiedMethodName; - - public SpoonTestMethod(CtType testClassModel, CtMethod testMethodModel) { - this.testClassModel = testClassModel; - this.testMethodModel = testMethodModel; - this.fullyQualifiedClassName = testClassModel.getQualifiedName(); - this.fullyQualifiedMethodName = fullyQualifiedClassName + "#" + testMethodModel.getSimpleName(); - } - - public CtType getTestClassModel() { - return testClassModel; - } - - public CtMethod getTestMethodModel() { - return testMethodModel; - } - - public String getFullyQualifiedClassName() { - return fullyQualifiedClassName; - } - - public String getFullyQualifiedMethodName() { - return fullyQualifiedMethodName; - } - - @Override - public String toString() { - return "[Spoon]TestMethod=" + getFullyQualifiedMethodName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass().getSuperclass() != o.getClass().getSuperclass()) return false; - TestMethod that = (TestMethod) o; - return Objects.equals(getFullyQualifiedMethodName(), that.getFullyQualifiedMethodName()); - } - - @Override - public int hashCode() { - return Objects.hash(getFullyQualifiedMethodName()); - } -} \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/StringTestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/StringTestMethod.java deleted file mode 100644 index 682c231f..00000000 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/StringTestMethod.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.spoonlabs.flacoco.core.test; - -import java.util.Objects; - -/** - * Contains all the information about a single test unit, such as the test class and method names - * - * @author andre15silva - */ -public class StringTestMethod implements TestMethod { - - private String fullyQualifiedClassName; - - private String simpleMethodName; - - public StringTestMethod(String fullyQualifiedClassName, String simpleMethodName) { - this.fullyQualifiedClassName = fullyQualifiedClassName; - this.simpleMethodName = simpleMethodName; - } - - public String getFullyQualifiedClassName() { - return fullyQualifiedClassName; - } - - public String getFullyQualifiedMethodName() { - return fullyQualifiedClassName + "#" + simpleMethodName; - } - - @Override - public String toString() { - return "[Manual]TestMethod=" + getFullyQualifiedMethodName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass().getSuperclass() != o.getClass().getSuperclass()) return false; - TestMethod that = (TestMethod) o; - return Objects.equals(getFullyQualifiedMethodName(), that.getFullyQualifiedMethodName()); - } - - @Override - public int hashCode() { - return Objects.hash(getFullyQualifiedMethodName()); - } -} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/TestContext.java b/src/main/java/fr/spoonlabs/flacoco/core/test/TestContext.java index f46bbb20..85b1b29b 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/TestContext.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/TestContext.java @@ -1,6 +1,7 @@ package fr.spoonlabs.flacoco.core.test; import fr.spoonlabs.flacoco.core.coverage.framework.TestFrameworkStrategy; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/TestDetector.java b/src/main/java/fr/spoonlabs/flacoco/core/test/TestDetector.java index 3a5d1c59..e340ead2 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/TestDetector.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/TestDetector.java @@ -1,17 +1,16 @@ package fr.spoonlabs.flacoco.core.test; -import eu.stamp_project.testrunner.test_framework.TestFramework; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy; import fr.spoonlabs.flacoco.core.coverage.framework.JUnit5Strategy; +import fr.spoonlabs.flacoco.core.test.method.StringTestMethod; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.ClassloaderStrategy; +import fr.spoonlabs.flacoco.core.test.strategies.testrunner.TestRunnerStrategy; import org.apache.log4j.Logger; -import spoon.Launcher; -import spoon.reflect.declaration.CtType; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * @author Matias Martinez @@ -35,7 +34,7 @@ public List getTests() { return this.tests; } else { // If neither, compute them - logger.debug("Detecting tests with Spoon."); + logger.debug("Running chosen test detection strategy: " + this.config.getTestDetectionStrategy()); this.tests = this.findTests(); return this.tests; } @@ -45,7 +44,7 @@ private List computeTests() { List result = new ArrayList<>(); if (!this.config.getjUnit4Tests().isEmpty()) { - TestContext jUnit4Context = new TestContext(new JUnit4Strategy()); + TestContext jUnit4Context = new TestContext(JUnit4Strategy.getInstance()); jUnit4Context.addTestMethods( config.getjUnit4Tests().stream() .map(x -> new StringTestMethod(x.split("#")[0], x.split("#")[1])) @@ -54,7 +53,7 @@ private List computeTests() { result.add(jUnit4Context); } if (!this.config.getjUnit5Tests().isEmpty()) { - TestContext jUnit5Context = new TestContext(new JUnit5Strategy()); + TestContext jUnit5Context = new TestContext(JUnit5Strategy.getInstance()); jUnit5Context.addTestMethods( config.getjUnit5Tests().stream() .map(x -> new StringTestMethod(x.split("#")[0], x.split("#")[1])) @@ -67,48 +66,13 @@ private List computeTests() { } private List findTests() { - // Create Spoon model to retrieve information about the tests - Launcher launcher = new Launcher(); - for (String dir : config.getSrcTestDir()) - launcher.addInputResource(dir); - launcher.getEnvironment().setComplianceLevel(config.getComplianceLevel()); - launcher.buildModel(); - - // Init test framework - TestFramework.init(launcher.getFactory()); - - TestContext jUnit4Context = new TestContext(new JUnit4Strategy()); - TestContext jUnit5Context = new TestContext(new JUnit5Strategy()); - - for (CtType ctType : TestFramework.getAllTestClasses()) { - - if (ctType.isAbstract()) { - continue; - } - // avoid passing non-qualified class names to test-runner - if (ctType.getPackage().isUnnamedPackage()) { - logger.warn("TestDetector was not able to retrieve the fully qualified class name of : " + ctType.getQualifiedName()); - continue; - } - - // Add JUnit4 methods to jUnit4Context - jUnit4Context.addTestMethods( - TestFramework.getAllTest(ctType).stream().filter(TestFramework::isJUnit4) - .map(ctMethod -> new SpoonTestMethod(ctType, ctMethod)) - .collect(Collectors.toList()) - ); - - // Add JUnit5 methods to jUnit5Context - jUnit5Context.addTestMethods( - TestFramework.getAllTest(ctType).stream().filter(TestFramework::isJUnit5) - .map(ctMethod -> new SpoonTestMethod(ctType, ctMethod)) - .collect(Collectors.toList()) - ); + switch (config.getTestDetectionStrategy()) { + case TEST_RUNNER: + return new TestRunnerStrategy().findTests(); + case CLASSLOADER: + default: + return new ClassloaderStrategy().findTests(); } - - // We only want to return those that have test units - return Stream.of(jUnit4Context, jUnit5Context) - .filter(x -> !x.getTestMethods().isEmpty()).collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/TestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/TestMethod.java deleted file mode 100644 index 834582a7..00000000 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/TestMethod.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.spoonlabs.flacoco.core.test; - -/** - * Test unit representation for flacoco - * - * @author andre15silva - */ -public interface TestMethod { - - String getFullyQualifiedClassName(); - - String getFullyQualifiedMethodName(); - -} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/method/SpoonTestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/method/SpoonTestMethod.java new file mode 100644 index 00000000..0d25c458 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/method/SpoonTestMethod.java @@ -0,0 +1,64 @@ +package fr.spoonlabs.flacoco.core.test.method; + +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; + +import java.util.Objects; + +/** + * Contains all the information about a single test unit in a Spoonful way, + * such as the test class and the method models + * + * @author andre15silva + */ +public class SpoonTestMethod implements TestMethod { + + private CtType testClassModel; + + private String fullyQualifiedClassName; + + private CtMethod testMethodModel; + + private String fullyQualifiedMethodName; + + public SpoonTestMethod(CtType testClassModel, CtMethod testMethodModel) { + this.testClassModel = testClassModel; + this.testMethodModel = testMethodModel; + this.fullyQualifiedClassName = testClassModel.getQualifiedName(); + this.fullyQualifiedMethodName = fullyQualifiedClassName + "#" + testMethodModel.getSimpleName(); + } + + public CtType getTestClassModel() { + return testClassModel; + } + + public CtMethod getTestMethodModel() { + return testMethodModel; + } + + public String getFullyQualifiedClassName() { + return fullyQualifiedClassName; + } + + public String getFullyQualifiedMethodName() { + return fullyQualifiedMethodName; + } + + @Override + public String toString() { + return "[Spoon]TestMethod=" + getFullyQualifiedMethodName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass().getSuperclass() != o.getClass().getSuperclass()) return false; + TestMethod that = (TestMethod) o; + return Objects.equals(getFullyQualifiedMethodName(), that.getFullyQualifiedMethodName()); + } + + @Override + public int hashCode() { + return Objects.hash(getFullyQualifiedMethodName()); + } +} \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/method/StringTestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/method/StringTestMethod.java new file mode 100644 index 00000000..d2e6919e --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/method/StringTestMethod.java @@ -0,0 +1,46 @@ +package fr.spoonlabs.flacoco.core.test.method; + +import java.util.Objects; + +/** + * Contains all the information about a single test unit, such as the test class and method names + * + * @author andre15silva + */ +public class StringTestMethod implements TestMethod { + + private String fullyQualifiedClassName; + + private String simpleMethodName; + + public StringTestMethod(String fullyQualifiedClassName, String simpleMethodName) { + this.fullyQualifiedClassName = fullyQualifiedClassName; + this.simpleMethodName = simpleMethodName; + } + + public String getFullyQualifiedClassName() { + return fullyQualifiedClassName; + } + + public String getFullyQualifiedMethodName() { + return fullyQualifiedClassName + "#" + simpleMethodName; + } + + @Override + public String toString() { + return "[Manual]TestMethod=" + getFullyQualifiedMethodName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass().getSuperclass() != o.getClass().getSuperclass()) return false; + TestMethod that = (TestMethod) o; + return Objects.equals(getFullyQualifiedMethodName(), that.getFullyQualifiedMethodName()); + } + + @Override + public int hashCode() { + return Objects.hash(getFullyQualifiedMethodName()); + } +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/method/TestMethod.java b/src/main/java/fr/spoonlabs/flacoco/core/test/method/TestMethod.java new file mode 100644 index 00000000..595a7497 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/method/TestMethod.java @@ -0,0 +1,14 @@ +package fr.spoonlabs.flacoco.core.test.method; + +/** + * Test unit representation for flacoco + * + * @author andre15silva + */ +public interface TestMethod { + + String getFullyQualifiedClassName(); + + String getFullyQualifiedMethodName(); + +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/TestDetectionStrategy.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/TestDetectionStrategy.java new file mode 100644 index 00000000..bb17145b --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/TestDetectionStrategy.java @@ -0,0 +1,11 @@ +package fr.spoonlabs.flacoco.core.test.strategies; + +import fr.spoonlabs.flacoco.core.test.TestContext; + +import java.util.List; + +public interface TestDetectionStrategy { + + public List findTests(); + +} \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/ClassloaderStrategy.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/ClassloaderStrategy.java new file mode 100644 index 00000000..10971da1 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/ClassloaderStrategy.java @@ -0,0 +1,64 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader; + +import fr.spoonlabs.flacoco.core.config.FlacocoConfig; +import fr.spoonlabs.flacoco.core.test.TestContext; +import fr.spoonlabs.flacoco.core.test.strategies.TestDetectionStrategy; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.CustomClassLoaderThreadFactory; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.TestFinderRunner; +import org.apache.log4j.Logger; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.*; + +/** + * Runs a new thread with the specified test binary directories as the classpath. + *

+ * Scans all available classes and filters them according to the JUnit specification. + */ +public class ClassloaderStrategy implements TestDetectionStrategy { + + private Logger logger = Logger.getLogger(ClassloaderStrategy.class); + private FlacocoConfig config = FlacocoConfig.getInstance(); + + @Override + public List findTests() { + try { + // Build urlClassLoader for new thread + URLClassLoader urlClassLoader = new URLClassLoader(getUrls()); + + // Run the new thread with the finder + ThreadFactory threadFactory = new CustomClassLoaderThreadFactory(urlClassLoader); + ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory); + Future> future = executor.submit(new TestFinderRunner()); + executor.shutdown(); + + return future.get(); + } catch (InterruptedException | ExecutionException | MalformedURLException e) { + throw new RuntimeException(e); + } + } + + private URL[] getUrls() throws MalformedURLException { + List urls = new ArrayList<>(); + // Build the classloader for the new thread + for (String dir : config.getBinJavaDir()) { + urls.add(new File(dir).toURI().toURL()); + } + for (String dir : config.getBinTestDir()) { + urls.add(new File(dir).toURI().toURL()); + } + System.out.println(config); + if (!config.getClasspath().isEmpty()) { + for (String dir : config.getClasspath().split(File.pathSeparator)) { + urls.add(new File(dir).toURI().toURL()); + } + } + System.out.println(urls); + return urls.toArray(new URL[0]); + } +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/CustomClassLoaderThreadFactory.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/CustomClassLoaderThreadFactory.java new file mode 100644 index 00000000..ff80c3f9 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/CustomClassLoaderThreadFactory.java @@ -0,0 +1,25 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +public final class CustomClassLoaderThreadFactory implements ThreadFactory { + + public CustomClassLoaderThreadFactory(ClassLoader customClassLoader) { + this.customClassLoader = customClassLoader; + } + + @Override + public Thread newThread(Runnable r) { + Thread newThread = Executors.defaultThreadFactory().newThread(r); + newThread.setDaemon(true); // use to avoid a main process to continue running waiting for this thread end at the end of execution + newThread.setContextClassLoader(customClassLoader()); + return newThread; + } + + private ClassLoader customClassLoader() { + return customClassLoader; + } + + private ClassLoader customClassLoader; +} \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java new file mode 100644 index 00000000..9adfa06c --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java @@ -0,0 +1,117 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder; + +import fr.spoonlabs.flacoco.core.test.method.TestMethod; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.ClassFinder; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.impl.ClassloaderFinder; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.filters.TestMethodFilter; +import org.apache.log4j.Logger; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Processor { + + private static final Logger logger = Logger.getLogger(Processor.class); + + private static final int CLASS_SUFFIX_LENGTH = ".class".length(); + private static final int JAVA_SUFFIX_LENGTH = ".java".length(); + + private final TestMethodFilter tester; + private final ClassFinder finder; + + public Processor(ClassFinder finder, TestMethodFilter tester) { + this.tester = tester; + this.finder = finder; + } + + public List process() { + List testMethods = new ArrayList<>(); + + for (String fileName : finder.getClasses()) { + String className; + if (isJavaFile(fileName)) { + className = classNameFromJava(fileName); + } else if (isClassFile(fileName)) { + className = classNameFromFile(fileName); + } else continue; + if (!className.contains("$")) + try { + Class clazz = Class.forName(className); + Thread.currentThread().getContextClassLoader().loadClass(className); + if (clazz.isLocalClass() || clazz.isAnonymousClass()) { + continue; + } + testMethods.addAll(tester.acceptClass(clazz)); + } catch (ClassNotFoundException cnfe) { + try { + ClassLoader tmp = Thread.currentThread().getContextClassLoader(); + Class clazz = Class.forName(className, false, tmp); + if (clazz.isLocalClass() || clazz.isAnonymousClass()) { + continue; + } + testMethods.addAll(tester.acceptClass(clazz)); + } catch (ClassNotFoundException cnfe2) { + Class clazz = null; + try { + clazz = Class.forName(className, false, ((ClassloaderFinder) finder).urlClassloader); + if (clazz.isLocalClass() || clazz.isAnonymousClass()) { + continue; + } + testMethods.addAll(tester.acceptClass(clazz)); + } catch (ClassNotFoundException e) { + logger.warn("ClassNotFoundException: " + className); + logger.warn(Arrays.toString(((ClassloaderFinder) finder).urlClassloader.getURLs())); + } + } catch (NoClassDefFoundError ncdfe) { + // ignore not instantiable classes + } + } catch (NoClassDefFoundError ncdfe) { + // ignore not instantiable classes + } + } + + return testMethods; + } + + private String classNameFromJava(String fileName) { + String s = replaceFileSeparators(cutOffExtension(fileName, JAVA_SUFFIX_LENGTH)); + while (s.startsWith(".")) + s = s.substring(1); + return s; + } + + private boolean isJavaFile(String fileName) { + return fileName.endsWith(".java"); + } + + private boolean isInnerClass(String className) { + return className.contains("$"); + } + + private boolean isClassFile(String classFileName) { + return classFileName.endsWith(".class"); + } + + private String classNameFromFile(String classFileName) { + String s = replaceFileSeparators(cutOffExtension(classFileName, CLASS_SUFFIX_LENGTH)); + while (s.startsWith(".")) + s = s.substring(1); + return s; + } + + private String replaceFileSeparators(String s) { + String result = s.replace(File.separatorChar, '.'); + if (File.separatorChar != '/') { + result = result.replace('/', '.'); + } + return result; + } + + private String cutOffExtension(String classFileName, int length) { + return classFileName.substring(0, classFileName.length() + - length); + } + +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/TestFinderRunner.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/TestFinderRunner.java new file mode 100644 index 00000000..dcdcb3c2 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/TestFinderRunner.java @@ -0,0 +1,38 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder; + +import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy; +import fr.spoonlabs.flacoco.core.coverage.framework.JUnit5Strategy; +import fr.spoonlabs.flacoco.core.test.TestContext; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.impl.ClassloaderFinder; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.filters.TestMethodFilter; +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.filters.TestType; + +import java.net.URLClassLoader; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TestFinderRunner implements Callable> { + + @Override + public List call() throws Exception { + URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); + ClassloaderFinder classloaderFinder = new ClassloaderFinder(classLoader); + + // collect JUnit4 compatible tests + Processor processor = new Processor(classloaderFinder, new TestMethodFilter(EnumSet.of(TestType.JUNIT3_TEST, TestType.JUNIT4_TEST))); + TestContext jUnit4Context = new TestContext(JUnit4Strategy.getInstance()); + jUnit4Context.addTestMethods(processor.process()); + + // collect JUnit5 compatible tests + processor = new Processor(classloaderFinder, new TestMethodFilter(EnumSet.of(TestType.JUNIT5_TEST))); + TestContext jUnit5Context = new TestContext(JUnit5Strategy.getInstance()); + jUnit5Context.addTestMethods(processor.process()); + + // We only want to return those that have test units + return Stream.of(jUnit4Context, jUnit5Context) + .filter(x -> !x.getTestMethods().isEmpty()).collect(Collectors.toList()); + } +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/ClassFinder.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/ClassFinder.java new file mode 100644 index 00000000..889857cd --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/ClassFinder.java @@ -0,0 +1,7 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes; + +public interface ClassFinder { + + String[] getClasses(); + +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java new file mode 100644 index 00000000..0c23f7fa --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java @@ -0,0 +1,28 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.impl; + +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.ClassFinder; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +public class ClassloaderFinder implements ClassFinder { + + public URLClassLoader urlClassloader; + + public ClassloaderFinder(URLClassLoader urlClassloader) { + this.urlClassloader = urlClassloader; + } + + @Override + public String[] getClasses() { + List classes = new ArrayList<>(); + for (URL url : urlClassloader.getURLs()) { + classes.addAll(SourceFolderFinder.getClassesLoc(new File(url.getPath()), null)); + } + return classes.toArray(new String[0]); + } + +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java new file mode 100644 index 00000000..f0510796 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java @@ -0,0 +1,46 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.impl; + +import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.ClassFinder; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + + +public class SourceFolderFinder implements ClassFinder { + + private String srcFolder; + + public SourceFolderFinder(String srcFolder) { + this.srcFolder = srcFolder; + } + + @Override + public String[] getClasses() { + return getClassesLoc(new File(srcFolder), null).toArray(new String[0]); + } + + // TODO: make this prettier + static List getClassesLoc(File testSrcFolder, String pack) { + List classes = new ArrayList<>(); + if (!testSrcFolder.isDirectory()) { + if (testSrcFolder.getName().endsWith(".java") || testSrcFolder.getName().endsWith(".class")) { + String className = pack == null ? testSrcFolder.getName() : pack + '.' + testSrcFolder.getName(); + classes.add(className); + } + } + + for (File file : testSrcFolder.listFiles()) { + if (file.isDirectory()) + classes.addAll(getClassesLoc(file, pack == null ? file.getName() : pack + '.' + file.getName())); + else if (file.getName().endsWith(".java")) { + String className = pack == null ? file.getName() : pack + '.' + file.getName(); + classes.add(className); + } else if (file.getName().endsWith(".class")) { + String className = pack == null ? file.getName() : pack + '.' + file.getName(); + classes.add(className); + } + } + return classes; + } +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestMethodFilter.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestMethodFilter.java new file mode 100644 index 00000000..c96f4304 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestMethodFilter.java @@ -0,0 +1,121 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.filters; + +import fr.spoonlabs.flacoco.core.test.method.StringTestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; +import junit.framework.TestCase; +import org.apache.log4j.Logger; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +public class TestMethodFilter { + + private static final Logger logger = Logger.getLogger(TestMethodFilter.class); + + private final EnumSet testTypes; + + public TestMethodFilter(EnumSet testTypes) { + this.testTypes = testTypes; + } + + public List acceptClass(Class clazz) { + List testMethods = new ArrayList<>(); + + // ignore abstract classes + if (isAbstractClass(clazz)) { + return testMethods; + } + + // check all available filters + if (isInSuiteTypes(TestType.JUNIT5_TEST)) { + testMethods.addAll(acceptJUnit5Test(clazz)); + } + if (isInSuiteTypes(TestType.JUNIT4_TEST)) { + testMethods.addAll(acceptJUnit4Test(clazz)); + } + if (isInSuiteTypes(TestType.JUNIT3_TEST)) { + testMethods.addAll(acceptJUnit3Test(clazz)); + } + + return testMethods; + } + + private List acceptJUnit3Test(Class clazz) { + List testMethods = new ArrayList<>(); + + try { + if (isPublicClass(clazz) && TestCase.class.isAssignableFrom(clazz)) { + for (Method method : clazz.getMethods()) { + if (isPublicMethod(method) + && !isStaticMethod(method) + && method.getReturnType() == void.class + // && no arguments + && method.getName().startsWith("test") + ) { + testMethods.add(new StringTestMethod(clazz.getCanonicalName(), method.getName())); + } + } + } + } catch (NoClassDefFoundError ignore) { + logger.warn("NoClassDefFoundError: " + clazz); + } + + return testMethods; + } + + private List acceptJUnit4Test(Class clazz) { + List testMethods = new ArrayList<>(); + + try { + for (Method method : clazz.getMethods()) { + if (method.getAnnotation(org.junit.Test.class) != null) { + testMethods.add(new StringTestMethod(clazz.getCanonicalName(), method.getName())); + } + } + } catch (NoClassDefFoundError ignore) { + logger.warn("NoClassDefFoundError: " + clazz); + } + + return testMethods; + } + + private List acceptJUnit5Test(Class clazz) { + List testMethods = new ArrayList<>(); + + try { + for (Method method : clazz.getMethods()) { + if (method.getAnnotation(org.junit.jupiter.api.Test.class) != null) { + testMethods.add(new StringTestMethod(clazz.getCanonicalName(), method.getName())); + } + } + } catch (NoClassDefFoundError ignore) { + logger.warn("NoClassDefFoundError: " + clazz); + } + + return testMethods; + } + + private boolean isAbstractClass(Class clazz) { + return (clazz.getModifiers() & Modifier.ABSTRACT) != 0; + } + + private boolean isPublicClass(Class clazz) { + return (clazz.getModifiers() & Modifier.PUBLIC) != 0; + } + + private boolean isPublicMethod(Method method) { + return (method.getModifiers() & Modifier.PUBLIC) != 0; + } + + private boolean isStaticMethod(Method method) { + return (method.getModifiers() & Modifier.STATIC) != 0; + } + + private boolean isInSuiteTypes(TestType testType) { + return testTypes.contains(testType); + } + +} diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestType.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestType.java new file mode 100644 index 00000000..423f4c45 --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/filters/TestType.java @@ -0,0 +1,7 @@ +package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.filters; + +public enum TestType { + JUNIT5_TEST, + JUNIT4_TEST, + JUNIT3_TEST +} \ No newline at end of file diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/testrunner/TestRunnerStrategy.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/testrunner/TestRunnerStrategy.java new file mode 100644 index 00000000..7972b0af --- /dev/null +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/testrunner/TestRunnerStrategy.java @@ -0,0 +1,76 @@ +package fr.spoonlabs.flacoco.core.test.strategies.testrunner; + +import eu.stamp_project.testrunner.test_framework.TestFramework; +import fr.spoonlabs.flacoco.core.config.FlacocoConfig; +import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy; +import fr.spoonlabs.flacoco.core.coverage.framework.JUnit5Strategy; +import fr.spoonlabs.flacoco.core.test.TestContext; +import fr.spoonlabs.flacoco.core.test.method.SpoonTestMethod; +import fr.spoonlabs.flacoco.core.test.strategies.TestDetectionStrategy; +import org.apache.log4j.Logger; +import spoon.Launcher; +import spoon.reflect.declaration.CtType; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Builds a Spoon model and uses test-runner's test framework detection API + * to detect tests and their corresponding frameworks + *

+ * Note: this strategy is considerably slower than ClasspathStrategy, and has + * some identified bugs (see https://github.com/SpoonLabs/flacoco/issues/80). + * Use at own risk. + */ +public class TestRunnerStrategy implements TestDetectionStrategy { + + private Logger logger = Logger.getLogger(TestRunnerStrategy.class); + private FlacocoConfig config = FlacocoConfig.getInstance(); + + @Override + public List findTests() { + // Create Spoon model to retrieve information about the tests + Launcher launcher = new Launcher(); + for (String dir : config.getSrcTestDir()) + launcher.addInputResource(dir); + launcher.getEnvironment().setComplianceLevel(config.getComplianceLevel()); + launcher.buildModel(); + + // Init test framework + TestFramework.init(launcher.getFactory()); + + TestContext jUnit4Context = new TestContext(JUnit4Strategy.getInstance()); + TestContext jUnit5Context = new TestContext(JUnit5Strategy.getInstance()); + + for (CtType ctType : TestFramework.getAllTestClasses()) { + + if (ctType.isAbstract()) { + continue; + } + // avoid passing non-qualified class names to test-runner + if (ctType.getPackage().isUnnamedPackage()) { + logger.warn("TestDetector was not able to retrieve the fully qualified class name of : " + ctType.getQualifiedName()); + continue; + } + + // Add JUnit4 methods to jUnit4Context + jUnit4Context.addTestMethods( + TestFramework.getAllTest(ctType).stream().filter(TestFramework::isJUnit4) + .map(ctMethod -> new SpoonTestMethod(ctType, ctMethod)) + .collect(Collectors.toList()) + ); + + // Add JUnit5 methods to jUnit5Context + jUnit5Context.addTestMethods( + TestFramework.getAllTest(ctType).stream().filter(TestFramework::isJUnit5) + .map(ctMethod -> new SpoonTestMethod(ctType, ctMethod)) + .collect(Collectors.toList()) + ); + } + + // We only want to return those that have test units + return Stream.of(jUnit4Context, jUnit5Context) + .filter(x -> !x.getTestMethods().isEmpty()).collect(Collectors.toList()); + } +} diff --git a/src/main/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputation.java b/src/main/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputation.java index 58989660..54c627e6 100644 --- a/src/main/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputation.java +++ b/src/main/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputation.java @@ -3,7 +3,7 @@ import fr.spoonlabs.flacoco.api.Suspiciousness; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.coverage.CoverageMatrix; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import fr.spoonlabs.flacoco.localization.spectrum.formulas.Formula; import org.apache.log4j.Logger; diff --git a/src/test/java/fr/spoonlabs/flacoco/api/FlacocoTest.java b/src/test/java/fr/spoonlabs/flacoco/api/FlacocoTest.java index f1542274..553f8f87 100644 --- a/src/test/java/fr/spoonlabs/flacoco/api/FlacocoTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/api/FlacocoTest.java @@ -774,7 +774,7 @@ public void testExampleFL7SpectrumBasedOchiaiDefaultMode() { public void testExampleFL8SpectrumBasedOchiaiDefaultMode() { // Setup config FlacocoConfig config = FlacocoConfig.getInstance(); - config.setProjectPath("./examples/exampleFL8NotMaven/"); + // we don't set --projectpath because it is not needed when we explicit the other 4 dirs config.setSrcJavaDir(Collections.singletonList("./examples/exampleFL8NotMaven/java")); config.setSrcTestDir(Collections.singletonList("./examples/exampleFL8NotMaven/test")); config.setBinJavaDir(Collections.singletonList("./examples/exampleFL8NotMaven/bin/classes")); diff --git a/src/test/java/fr/spoonlabs/flacoco/cli/FlacocoMainTest.java b/src/test/java/fr/spoonlabs/flacoco/cli/FlacocoMainTest.java index 2ff6fae1..b938f2f8 100644 --- a/src/test/java/fr/spoonlabs/flacoco/cli/FlacocoMainTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/cli/FlacocoMainTest.java @@ -97,10 +97,11 @@ public void testMainExplicitArgumentsNotMaven() { exit.expectSystemExitWithStatus(0); FlacocoMain.main(new String[]{ // we don't set --projectpath because it is not needed when we explicit the other 4 dirs - "--srcJavaDir", "examples/exampleFL8/java", - "--srcTestDir", "examples/exampleFL8/test", - "--binJavaDir", "examples/exampleFL8/bin/classes", - "--binTestDir", "examples/exampleFL8/bin/test-classes", + "--srcJavaDir", "examples/exampleFL8NotMaven/java", + "--srcTestDir", "examples/exampleFL8NotMaven/test", + "--binJavaDir", "examples/exampleFL8NotMaven/bin/classes", + "--binTestDir", "examples/exampleFL8NotMaven/bin/test-classes", + "--testDetectionStrategy", FlacocoConfig.TestDetectionStrategy.CLASSLOADER.name(), "--formula", SpectrumFormula.OCHIAI.name(), "--mavenHome", mavenHome, "--junitClasspath", junitClasspath, diff --git a/src/test/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunnerTest.java b/src/test/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunnerTest.java index 29918f89..7b0cb43c 100644 --- a/src/test/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunnerTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/core/coverage/CoverageRunnerTest.java @@ -4,7 +4,7 @@ import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.test.TestContext; import fr.spoonlabs.flacoco.core.test.TestDetector; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Level; import org.apache.log4j.LogManager; import org.junit.*; diff --git a/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java b/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java index 3146c712..d8e3b7ed 100644 --- a/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java @@ -3,9 +3,14 @@ import fr.spoonlabs.flacoco.core.config.FlacocoConfig; import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy; import fr.spoonlabs.flacoco.core.coverage.framework.JUnit5Strategy; +import fr.spoonlabs.flacoco.core.test.method.StringTestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Level; import org.apache.log4j.LogManager; -import org.junit.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; @@ -83,6 +88,25 @@ public void testExampleFL1ManualConfig() { assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); } + @Test + public void testExampleFL1TestRunnerDetector() { + // Setup config + FlacocoConfig config = FlacocoConfig.getInstance(); + config.setProjectPath(new File("./examples/exampleFL1/FLtest1").getAbsolutePath()); + config.setTestDetectionStrategy(FlacocoConfig.TestDetectionStrategy.TEST_RUNNER); + + // Find the tests + TestDetector testDetector = new TestDetector(); + List testContexts = testDetector.getTests(); + + // Check that there is only one test context + assertEquals(1, testContexts.size()); + // Check that there are 4 test methods in the test context + TestContext testContext = testContexts.get(0); + assertEquals(4, testContext.getTestMethods().size()); + // Check that the correct test framework is set + assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); + } @Test public void testExampleFL2() { @@ -382,9 +406,7 @@ public void testExampleFL12() { assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); } - // TODO: Fix this https://github.com/SpoonLabs/flacoco/issues/80 @Test - @Ignore public void testMath70() { // Setup config FlacocoConfig config = FlacocoConfig.getInstance(); diff --git a/src/test/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputationTest.java b/src/test/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputationTest.java index 3684fa50..56dd6ce4 100644 --- a/src/test/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputationTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/localization/spectrum/SpectrumSuspiciousComputationTest.java @@ -2,7 +2,7 @@ import fr.spoonlabs.flacoco.api.Suspiciousness; import fr.spoonlabs.flacoco.core.coverage.CoverageMatrix; -import fr.spoonlabs.flacoco.core.test.TestMethod; +import fr.spoonlabs.flacoco.core.test.method.TestMethod; import fr.spoonlabs.flacoco.localization.spectrum.formulas.OchiaiFormula; import org.junit.BeforeClass; import org.junit.Test; From 0e14994a99cae0e7815bd980e77f92c43ff699f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 13 Aug 2021 10:39:38 +0200 Subject: [PATCH 2/3] Fix class finder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Silva --- pom.xml | 7 +++++ .../classloader/finder/Processor.java | 9 +----- .../classes/impl/ClassloaderFinder.java | 2 +- .../classes/impl/SourceFolderFinder.java | 30 ++++--------------- 4 files changed, 15 insertions(+), 33 deletions(-) diff --git a/pom.xml b/pom.xml index 67fd7f6e..c24ab265 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,13 @@ 3.11.2 test + + + + org.apache.maven.surefire + maven-surefire-common + 3.0.0-M5 + diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java index 9adfa06c..9a60284d 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/Processor.java @@ -29,17 +29,10 @@ public Processor(ClassFinder finder, TestMethodFilter tester) { public List process() { List testMethods = new ArrayList<>(); - for (String fileName : finder.getClasses()) { - String className; - if (isJavaFile(fileName)) { - className = classNameFromJava(fileName); - } else if (isClassFile(fileName)) { - className = classNameFromFile(fileName); - } else continue; + for (String className : finder.getClasses()) { if (!className.contains("$")) try { Class clazz = Class.forName(className); - Thread.currentThread().getContextClassLoader().loadClass(className); if (clazz.isLocalClass() || clazz.isAnonymousClass()) { continue; } diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java index 0c23f7fa..8bd7fc9f 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/ClassloaderFinder.java @@ -20,7 +20,7 @@ public ClassloaderFinder(URLClassLoader urlClassloader) { public String[] getClasses() { List classes = new ArrayList<>(); for (URL url : urlClassloader.getURLs()) { - classes.addAll(SourceFolderFinder.getClassesLoc(new File(url.getPath()), null)); + classes.addAll(SourceFolderFinder.getClassesLoc(new File(url.getPath()))); } return classes.toArray(new String[0]); } diff --git a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java index f0510796..72985228 100644 --- a/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java +++ b/src/main/java/fr/spoonlabs/flacoco/core/test/strategies/classloader/finder/classes/impl/SourceFolderFinder.java @@ -1,9 +1,10 @@ package fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.impl; import fr.spoonlabs.flacoco.core.test.strategies.classloader.finder.classes.ClassFinder; +import org.apache.maven.plugin.surefire.util.DirectoryScanner; +import org.apache.maven.surefire.api.testset.TestListResolver; import java.io.File; -import java.util.ArrayList; import java.util.List; @@ -17,30 +18,11 @@ public SourceFolderFinder(String srcFolder) { @Override public String[] getClasses() { - return getClassesLoc(new File(srcFolder), null).toArray(new String[0]); + return getClassesLoc(new File(srcFolder)).toArray(new String[0]); } - // TODO: make this prettier - static List getClassesLoc(File testSrcFolder, String pack) { - List classes = new ArrayList<>(); - if (!testSrcFolder.isDirectory()) { - if (testSrcFolder.getName().endsWith(".java") || testSrcFolder.getName().endsWith(".class")) { - String className = pack == null ? testSrcFolder.getName() : pack + '.' + testSrcFolder.getName(); - classes.add(className); - } - } - - for (File file : testSrcFolder.listFiles()) { - if (file.isDirectory()) - classes.addAll(getClassesLoc(file, pack == null ? file.getName() : pack + '.' + file.getName())); - else if (file.getName().endsWith(".java")) { - String className = pack == null ? file.getName() : pack + '.' + file.getName(); - classes.add(className); - } else if (file.getName().endsWith(".class")) { - String className = pack == null ? file.getName() : pack + '.' + file.getName(); - classes.add(className); - } - } - return classes; + static List getClassesLoc(File testSrcFolder) { + DirectoryScanner directoryScanner = new DirectoryScanner(testSrcFolder, TestListResolver.getWildcard()); + return directoryScanner.scan().getClasses(); } } From dd621c1ea7fc4daf390cc603ee85b5878fb3b180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Fri, 13 Aug 2021 10:50:15 +0200 Subject: [PATCH 3/3] Fix conditional test ignore according to JVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Silva --- .../fr/spoonlabs/flacoco/api/Math70Test.java | 33 ++++++++++++++++--- .../flacoco/core/test/TestDetectorTest.java | 30 ++++------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/test/java/fr/spoonlabs/flacoco/api/Math70Test.java b/src/test/java/fr/spoonlabs/flacoco/api/Math70Test.java index a934c176..51d3f189 100644 --- a/src/test/java/fr/spoonlabs/flacoco/api/Math70Test.java +++ b/src/test/java/fr/spoonlabs/flacoco/api/Math70Test.java @@ -1,6 +1,9 @@ package fr.spoonlabs.flacoco.api; import fr.spoonlabs.flacoco.core.config.FlacocoConfig; +import fr.spoonlabs.flacoco.core.coverage.framework.JUnit4Strategy; +import fr.spoonlabs.flacoco.core.test.TestContext; +import fr.spoonlabs.flacoco.core.test.TestDetector; import fr.spoonlabs.flacoco.localization.spectrum.SpectrumFormula; import org.apache.log4j.Level; import org.apache.log4j.LogManager; @@ -8,10 +11,12 @@ import org.junit.rules.TemporaryFolder; import java.io.File; +import java.util.List; import java.util.Map; import static fr.spoonlabs.flacoco.TestUtils.getJavaVersion; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * This test class tests the execution of Flacoco on Math70 @@ -23,8 +28,10 @@ public class Math70Test { @Before public void setUp() { - LogManager.getRootLogger().setLevel(Level.DEBUG); + // Run only on Java8 + Assume.assumeTrue(getJavaVersion() == 8); + LogManager.getRootLogger().setLevel(Level.DEBUG); FlacocoConfig config = FlacocoConfig.getInstance(); config.setWorkspace(workspaceDir.getRoot().getAbsolutePath()); config.setTestRunnerVerbose(true); @@ -37,9 +44,6 @@ public void tearDown() { @Test public void testMath70() { - // Run only on Java8 - Assume.assumeTrue(getJavaVersion() == 8); - // Setup config FlacocoConfig config = FlacocoConfig.getInstance(); config.setProjectPath(new File("./examples/math_70").getAbsolutePath()); @@ -68,4 +72,25 @@ public void testMath70() { assertEquals(0.5, susp.get("org/apache/commons/math/analysis/solvers/BisectionSolver@-@87").getScore(), 0); assertEquals(0.5, susp.get("org/apache/commons/math/analysis/solvers/BisectionSolver@-@87").getScore(), 0); } + + + @Test + public void testMath70TestDetection() { + // Setup config + FlacocoConfig config = FlacocoConfig.getInstance(); + config.setProjectPath(new File("./examples/math_70").getAbsolutePath()); + config.setComplianceLevel(4); + + // Find the tests + TestDetector testDetector = new TestDetector(); + List testContexts = testDetector.getTests(); + + // Check that there is only one test context + assertEquals(1, testContexts.size()); + // Check that there are 2181 test methods in the test context + TestContext testContext = testContexts.get(0); + assertEquals(2181, testContext.getTestMethods().size()); + // Check that the correct test framework is set + assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); + } } diff --git a/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java b/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java index d8e3b7ed..70bd3404 100644 --- a/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java +++ b/src/test/java/fr/spoonlabs/flacoco/core/test/TestDetectorTest.java @@ -7,10 +7,7 @@ import fr.spoonlabs.flacoco.core.test.method.TestMethod; import org.apache.log4j.Level; import org.apache.log4j.LogManager; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.rules.TemporaryFolder; import java.io.File; @@ -18,6 +15,7 @@ import java.util.Collections; import java.util.List; +import static fr.spoonlabs.flacoco.TestUtils.isLessThanJava11; import static org.junit.Assert.*; /** @@ -388,6 +386,10 @@ public void testExampleFL11() { @Test public void testExampleFL12() { + // We can only run this test on java version less than 11 + // since java 11 dropped support for compliance level 1.4 + Assume.assumeTrue(isLessThanJava11()); + // Setup config FlacocoConfig config = FlacocoConfig.getInstance(); config.setProjectPath(new File("./examples/exampleFL12Compliance4/FLtest1").getAbsolutePath()); @@ -406,24 +408,4 @@ public void testExampleFL12() { assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); } - @Test - public void testMath70() { - // Setup config - FlacocoConfig config = FlacocoConfig.getInstance(); - config.setProjectPath(new File("./examples/math_70").getAbsolutePath()); - config.setComplianceLevel(4); - - // Find the tests - TestDetector testDetector = new TestDetector(); - List testContexts = testDetector.getTests(); - - // Check that there is only one test context - assertEquals(1, testContexts.size()); - // Check that there are 2181 test methods in the test context - TestContext testContext = testContexts.get(0); - assertEquals(2181, testContext.getTestMethods().size()); - // Check that the correct test framework is set - assertTrue(testContext.getTestFrameworkStrategy() instanceof JUnit4Strategy); - } - } \ No newline at end of file