diff --git a/.travis.yml b/.travis.yml
index 439fada..f8d0631 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,7 +15,8 @@ matrix:
dist: bionic
before_install:
-- git clone https://github.com/spideruci/primitive-hamcrest.git
+- git clone https://github.com/spideruci/projects4testing.git
+- git clone https://github.com/spideruci/primitive-hamcrest.git
- cd primitive-hamcrest
- mvn install
- cd ..
diff --git a/pom.xml b/pom.xml
index e0c7714..2bb1fd5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,6 +11,8 @@
UTF-8
UTF-8
+ 5.6.0
+ 4.12
tacoco the per testcase junit runner
@@ -147,9 +149,37 @@
org.apache.maven.shared
maven-invoker
- 3.0.1
+ 3.0.1
-
+
+ org.junit.platform
+ junit-platform-launcher
+ 1.6.0
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.jupiter.version}
+ runtime
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ ${junit.jupiter.version}
+ runtime
+
+
+ com.github.testng-team
+ testng-junit5
+ 0.0.1
+ runtime
+
+
@@ -200,6 +230,22 @@
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.4.0
+
+
+ integration-test
+
+ exec
+
+
+ ${basedir}/tacoco-diagnoses
+
+
+
+
diff --git a/src/main/java/org/spideruci/tacoco/testlisteners/UnifiedTestListenerAdapter.java b/src/main/java/org/spideruci/tacoco/testlisteners/UnifiedTestListenerAdapter.java
new file mode 100644
index 0000000..8f9aa8d
--- /dev/null
+++ b/src/main/java/org/spideruci/tacoco/testlisteners/UnifiedTestListenerAdapter.java
@@ -0,0 +1,58 @@
+package org.spideruci.tacoco.testlisteners;
+
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.engine.TestExecutionResult.Status;
+import org.junit.platform.launcher.TestExecutionListener;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+
+public class UnifiedTestListenerAdapter implements TestExecutionListener {
+
+ private final ITacocoTestListener listener;
+ public UnifiedTestListenerAdapter(final ITacocoTestListener listener) {
+ this.listener = listener;
+ }
+
+ private String getUniqueTestName(TestIdentifier testIdentifier) {
+ final String testUid = testIdentifier.getUniqueId();
+ final String testName = testIdentifier.getDisplayName();
+ final String testUniqueName = String.format("%s.%s", testName, testUid);
+ return testUniqueName;
+ }
+
+ @Override
+ public void executionStarted(final TestIdentifier testIdentifier) {
+ final String testUniqueName = getUniqueTestName(testIdentifier);
+ listener.onTestStart(testUniqueName);
+ }
+
+ @Override
+ public void executionSkipped(final TestIdentifier testIdentifier, final String reason) {
+ listener.onTestSkipped();
+ }
+
+ @Override
+ public void executionFinished(final TestIdentifier testIdentifier, final TestExecutionResult testExecutionResult) {
+ final Status status = testExecutionResult.getStatus();
+
+ switch (status) {
+ case SUCCESSFUL:
+ listener.onTestPassed();
+ break;
+ case FAILED:
+ case ABORTED:
+ listener.onTestFailed();
+ break;
+ }
+
+ listener.onTestEnd();
+ }
+
+ public void testPlanExecutionStarted(final TestPlan testPlan) {
+ listener.onStart();
+ }
+
+ public void testPlanExecutionFinished(final TestPlan testPlan) {
+ listener.onEnd();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/spideruci/tacoco/testrunners/AbstractTestRunner.java b/src/main/java/org/spideruci/tacoco/testrunners/AbstractTestRunner.java
index d4814d9..d3f850e 100644
--- a/src/main/java/org/spideruci/tacoco/testrunners/AbstractTestRunner.java
+++ b/src/main/java/org/spideruci/tacoco/testrunners/AbstractTestRunner.java
@@ -2,11 +2,6 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.Callable;
import org.spideruci.tacoco.analysis.AnalysisResults;
@@ -17,7 +12,7 @@
public abstract class AbstractTestRunner {
- public static enum TestType {JUNIT, TESTNG, UNKNOWN};
+ public static enum TestType {JUNIT, TESTNG, UNIFIED, UNKNOWN};
public static boolean LOGGING = false;
@@ -31,39 +26,44 @@ public static enum TestType {JUNIT, TESTNG, UNKNOWN};
public abstract Callable getExecutableTest(Class> test);
public abstract void printTestRunSummary(AnalysisResults results);
- public static AbstractTestRunner getInstance(AbstractBuildProbe probe) {
- for(String test : probe.getTestClasses()){
+ public static AbstractTestRunner getInstance(final AbstractBuildProbe probe) {
+ for(final String test : probe.getTestClasses()){
try {
switch(getTestType(Class.forName(test))){
case JUNIT:
return new JUnitRunner();
case TESTNG:
return new TestNGRunner();
+ case UNIFIED:
+ return new UnifiedTestRunner();
case UNKNOWN:
continue;
}
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
- private static TestType getTestType(Class> test){
+ private static TestType getTestType(final Class> test){
- if(test == null) {
+ if(test == null || Modifier.isAbstract(test.getModifiers())) {
return TestType.UNKNOWN;
}
-
- if(Modifier.isAbstract(test.getModifiers())) {
- return TestType.UNKNOWN;
+
+ if (UnifiedTestRunner.containsExecutableTest(test)) {
+ // We are going to give the UnifiedTestRunner first dibs.
+ // If it is able to find any executable test, then we run with it
+ // else, fall back on the individual test types
+ return TestType.UNIFIED; // UnifiedTestRunner
}
if(junit.framework.TestCase.class.isAssignableFrom(test)) {
return TestType.JUNIT; //JUnit3
}
- for(Method testMethod : test.getMethods()) {
+ for(final Method testMethod : test.getMethods()) {
if(testMethod.getAnnotation(org.junit.Test.class) != null){
return TestType.JUNIT; //JUnit4
}
diff --git a/src/main/java/org/spideruci/tacoco/testrunners/UnifiedTestRunner.java b/src/main/java/org/spideruci/tacoco/testrunners/UnifiedTestRunner.java
new file mode 100644
index 0000000..0e2b59e
--- /dev/null
+++ b/src/main/java/org/spideruci/tacoco/testrunners/UnifiedTestRunner.java
@@ -0,0 +1,153 @@
+package org.spideruci.tacoco.testrunners;
+
+import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+
+import java.util.concurrent.Callable;
+
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TestPlan;
+import org.junit.platform.launcher.core.LauncherFactory;
+import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
+import org.junit.platform.launcher.listeners.TestExecutionSummary;
+import org.junit.platform.launcher.listeners.TestExecutionSummary.Failure;
+import org.spideruci.tacoco.analysis.AnalysisResults;
+import org.spideruci.tacoco.testlisteners.ITacocoTestListener;
+import org.spideruci.tacoco.testlisteners.UnifiedTestListenerAdapter;
+
+public class UnifiedTestRunner extends AbstractTestRunner {
+
+ private final static String TEST_CLASS_NAME = "test-class-name";
+ private final static String TEST_SUMMARY = "test-summary";
+
+ final Launcher launcher = LauncherFactory.create();
+
+
+ public static boolean containsExecutableTest(final Class> test, final boolean doSanityDryRun) {
+ try {
+ final LauncherDiscoveryRequest discoveryRequest = request().selectors(selectClass(test)).build();
+ final Launcher launcher = LauncherFactory.create();
+ final TestPlan testplan = launcher.discover(discoveryRequest);
+ final boolean containsTests = testplan.containsTests();
+
+ if (containsTests && doSanityDryRun) {
+ // the idea here is this: if this *silent* execute call
+ // throws any exception then we will return false in the catch
+ // block below. This is a silent execute call because it does
+ // not register any listeners at any point.
+ launcher.execute(testplan);
+ }
+
+ return containsTests;
+ } catch (final Exception e) {
+ return false;
+ }
+ }
+
+ public static boolean containsExecutableTest(final Class> test) {
+ return containsExecutableTest(test, false);
+ }
+
+ private LauncherDiscoveryRequest discoveryRequest(final Class> test) {
+ try {
+ final LauncherDiscoveryRequest discoveryRequest = request().selectors(selectClass(test)).build();
+ return discoveryRequest;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ public boolean shouldRun(final Class> test) {
+ return UnifiedTestRunner.containsExecutableTest(test);
+ }
+
+ @Override
+ public void listenThrough(final ITacocoTestListener listener) {
+ final UnifiedTestListenerAdapter testListenerAdapter = new UnifiedTestListenerAdapter(listener);
+ launcher.registerTestExecutionListeners(testListenerAdapter);
+ }
+
+ @Override
+ public Callable getExecutableTest(final Class> test) {
+ final LauncherDiscoveryRequest discoveryRequest = this.discoveryRequest(test);
+ final Launcher launcher = this.launcher;
+ final String testClassName = test.getName();
+
+ final Callable execTest = new Callable() {
+
+ @Override
+ public AnalysisResults call() throws Exception {
+ try {
+ if (discoveryRequest == null) {
+ return null;
+ }
+
+ final SummaryGeneratingListener sGeneratingListener = new SummaryGeneratingListener();
+
+ launcher.execute(discoveryRequest, sGeneratingListener);
+ final TestExecutionSummary summary = sGeneratingListener.getSummary();
+
+ final AnalysisResults results = new AnalysisResults();
+ results.put(TEST_CLASS_NAME, testClassName);
+ results.put(TEST_SUMMARY, summary);
+ return results;
+ } catch(Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ };
+
+ return execTest;
+ }
+
+ @Override
+ public void printTestRunSummary(final AnalysisResults results) {
+ if (results == null || results.iterator() == null || !results.iterator().hasNext()) {
+ return;
+ }
+
+ final TestExecutionSummary summary = results.get(TEST_SUMMARY);
+ if (summary == null) {
+ return;
+ }
+
+ final String testName = results.get(TEST_CLASS_NAME);
+ if (testName == null) {
+ return;
+ }
+
+ try {
+ this.testRunTime = (summary.getTimeFinished() - summary.getTimeStarted()) / 1000.0;
+ this.executedTestCount = (int) summary.getTestsStartedCount();
+ this.failedTestCount = (int) (summary.getTestsFailedCount() + summary.getTestsAbortedCount());
+ this.ignoredTestCount = (int) summary.getTestsSkippedCount();
+
+ System.out.println("Finishing " + testName + " Tests run: " + executedTestCount + " Failures: "
+ + failedTestCount + " Errors: " + summary.getTestsAbortedCount() + " Skipped: " + ignoredTestCount
+ + " Time elapsed: " + testRunTime + "sec");
+
+ if (this.failedTestCount != 0) {
+ System.out.println("---------------------Failures--------------------");
+ for (final Failure f : summary.getFailures()) {
+ System.out.println("Test Name: " + f.getTestIdentifier().getDisplayName());
+ System.out.println("Test Identifier: " + f.getTestIdentifier().getUniqueId());
+
+ System.out.println("Message: " + f.getException().getMessage());
+ System.out.println("Description: " + f.getException().getCause());
+ System.out.println("Trace: ");
+ f.getException().printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("---------------------Tacoco Error--------------------");
+ System.err.printf("Failed to parse Analysis Results for testName: %s\n", testName);
+ e.printStackTrace();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/tacoco-diagnoses b/tacoco-diagnoses
new file mode 100755
index 0000000..df7ad12
--- /dev/null
+++ b/tacoco-diagnoses
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+tacoco_home=$(pwd)
+projects4testing=$tacoco_home/projects4testing
+
+ls -alh .
+ls -alh $projects4testing/
+
+cd $projects4testing/spiderMath_Gradle && gradle build
+cd $projects4testing/spiderMath_JUnit4 && mvn clean compile test-compile -Dmaven.compiler.source=1.8 -Dmaven.compiler.target=1.8
+cd $projects4testing/spiderMath_TestNG && mvn clean compile test-compile -Dmaven.compiler.source=1.8 -Dmaven.compiler.target=1.8
+
+cd $tacoco_home
+
+mvn exec:java -Plauncher -Dtacoco.sut=$projects4testing/spiderMath_Gradle -Dtacoco.home=$tacoco_home -Dtacoco.project=spiderMath_Gradle -Danalyzer.opts="configs/tacoco-analyzer.config"
+
+if [ $? -ne 0 ];
+then
+ echo "Tacoco failed with spiderMath_Gradle..."
+ exit 1
+fi
+
+mvn exec:java -Plauncher -Dtacoco.sut=$projects4testing/spiderMath_TestNG -Dtacoco.home=$tacoco_home -Dtacoco.project=spiderMath_TestNG -Danalyzer.opts="configs/tacoco-analyzer.config"
+
+if [ $? -ne 0 ];
+then
+ echo "Tacoco failed with spiderMath_TestNG..."
+ exit 1
+fi
+
+mvn exec:java -Plauncher -Dtacoco.sut=$projects4testing/spiderMath_JUnit4 -Dtacoco.home=$tacoco_home -Dtacoco.project=spiderMath_JUnit4 -Danalyzer.opts="configs/tacoco-analyzer.config"
+
+if [ $? -ne 0 ];
+then
+ echo "Tacoco failed with spiderMath_JUnit4..."
+ exit 1
+fi
+
+mvn exec:java -Plauncher -Dtacoco.sut=$projects4testing/spiderMath_JUnit4_single_module -Dtacoco.home=$tacoco_home -Dtacoco.project=spiderMath_JUnit4_single_module -Danalyzer.opts="configs/tacoco-analyzer.config"
+
+if [ $? -ne 0 ];
+then
+ echo "Tacoco failed with spiderMath_JUnit4_single_module..."
+ exit 1
+fi
+
+exit 0
\ No newline at end of file