Skip to content

Commit

Permalink
feat: run on pure junit3 and junit5 (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
danglotb authored May 10, 2022
1 parent cfc540a commit 922bc6a
Show file tree
Hide file tree
Showing 14 changed files with 305 additions and 78 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<developers>
<developer>
<name>Benjamin Danglot</name>
<email>benjamin.danglot@inria.fr</email>
<email>benjamin.danglot@davidson.fr</email>
<organization>STAMP-project</organization>
<organizationUrl>https://www.stamp-project.eu/view/main/</organizationUrl>
</developer>
Expand Down
42 changes: 34 additions & 8 deletions src/main/java/eu/stamp_project/testrunner/EntryPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.apache.commons.io.IOUtils;
import org.jacoco.agent.rt.RT;
import org.jacoco.core.runtime.IRuntime;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.objectweb.asm.ClassReader;
import org.opentest4j.TestAbortedException;
Expand Down Expand Up @@ -286,6 +287,7 @@ public static TestResult runTests(String classpath, String[] fullQualifiedNameOf
+ String.join(ConstantsHelper.PATH_SEPARATOR, EntryPoint.blackList)),
ParserOptions.FLAG_nbFailingLoadClass, "" + nbFailingLoadClass
);
classpath = checkAndAddJUnit(classpath);
final String javaCommand = String.join(ConstantsHelper.WHITE_SPACE,
new String[]{getJavaCommand(),
(classpath + ConstantsHelper.PATH_SEPARATOR + ABSOLUTE_PATH_TO_RUNNER_CLASSES).replaceAll(" ", "%20"),
Expand All @@ -297,6 +299,23 @@ public static TestResult runTests(String classpath, String[] fullQualifiedNameOf
return EntryPoint.runTests(javaCommand);
}

private static String checkAndAddJUnit(String classpath) {
if (!classpath.contains("junit-4")) {
LOGGER.warn("junit-4 is not detected in the provided classpath.");
LOGGER.warn("junit-4 is mandatory, and will be artificially injected at he end of the provided classpath.");
final String junit4Path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
LOGGER.warn("junit-4 has been found here {}", junit4Path);
final String hamcrestPath = org.hamcrest.Description.class.getProtectionDomain().getCodeSource().getLocation().getPath();
LOGGER.warn("hamcrest has been found here {}", hamcrestPath);
classpath += ConstantsHelper.PATH_SEPARATOR + junit4Path + ConstantsHelper.PATH_SEPARATOR + hamcrestPath;
}
if (EntryPoint.jUnit5Mode) {
final String junit5PlatformLauncherPath = org.junit.platform.launcher.TestExecutionListener.class.getProtectionDomain().getCodeSource().getLocation().getPath();
classpath += ConstantsHelper.PATH_SEPARATOR + junit5PlatformLauncherPath;
}
return classpath;
}

private static TestResult runTests(String commandLine) throws TimeoutException {
try {
runGivenCommandLine(commandLine);
Expand Down Expand Up @@ -392,6 +411,7 @@ public static Coverage runCoverage(String classpath,
+ EntryPoint.coverageDetail.name()),
ParserOptions.FLAG_nbFailingLoadClass, "" + nbFailingLoadClass
);
classpath = checkAndAddJUnit(classpath);
final String javaCommand = String.join(ConstantsHelper.WHITE_SPACE,
new String[]{getJavaCommand(),
(classpath + ConstantsHelper.PATH_SEPARATOR + ABSOLUTE_PATH_TO_RUNNER_CLASSES
Expand Down Expand Up @@ -502,6 +522,7 @@ public static CoveragePerTestMethod runCoveragePerTestMethods(String classpath,
+ EntryPoint.coverageDetail.name()),
ParserOptions.FLAG_nbFailingLoadClass, "" + nbFailingLoadClass
);
classpath = checkAndAddJUnit(classpath);
final String javaCommand = String.join(ConstantsHelper.WHITE_SPACE,
new String[]{
getJavaCommand(),
Expand Down Expand Up @@ -610,6 +631,7 @@ public static CoveredTestResultPerTestMethod runCoveredTestResultPerTestMethods(
+ EntryPoint.coverageDetail.name()),
ParserOptions.FLAG_nbFailingLoadClass, "" + nbFailingLoadClass
);
classpath = checkAndAddJUnit(classpath);
final String javaCommand = String.join(ConstantsHelper.WHITE_SPACE,
new String[]{
getJavaCommand(),
Expand Down Expand Up @@ -686,7 +708,6 @@ public static CoveredTestResultPerTestMethod runOnlineCoveredTestResultPerTestMe
} catch (IOException e) {
throw new RuntimeException(e);
}

final String options = checkUseOptionsFile(
ParserOptions.FLAG_pathToCompiledClassesOfTheProject,
targetSourceClasses.stream().reduce((x, y) -> x + ConstantsHelper.PATH_SEPARATOR + y).get().replaceAll(" ", "%20"),
Expand All @@ -704,6 +725,7 @@ public static CoveredTestResultPerTestMethod runOnlineCoveredTestResultPerTestMe
+ EntryPoint.coverageDetail.name()),
ParserOptions.FLAG_nbFailingLoadClass, "" + nbFailingLoadClass
);
classpath = checkAndAddJUnit(classpath);
final String javaCommand = String.join(ConstantsHelper.WHITE_SPACE,
new String[]{
getJavaCommand(),
Expand Down Expand Up @@ -824,13 +846,17 @@ private static void runGivenCommandLine(String commandLine) throws TimeoutExcept
long startTime = System.currentTimeMillis();
boolean finished = process.waitFor(timeoutInMs, TimeUnit.MILLISECONDS);
long endTime = System.currentTimeMillis();
int exitValue = process.exitValue();
if (!finished || exitValue != 0) {
throw new RuntimeException("Forked process did not finish correctly.\n" +
"Timeout set was " + timeoutInMs + " ms, " +
"process took " + (endTime - startTime) + " ms before ending.\n" +
"Use the verbose mode to obtain more information regarding the error."
);
try {
int exitValue = process.exitValue();
if (!finished || exitValue != 0) {
throw new RuntimeException("Forked process did not finish correctly.\n" +
"Timeout set was " + timeoutInMs + " ms, " +
"process took " + (endTime - startTime) + " ms before ending.\n" +
"Use the verbose mode to obtain more information regarding the error."
);
}
} catch (IllegalThreadStateException ignored) {
ignored.printStackTrace();
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,53 +20,44 @@
*/
public class CoverageCollectorDetailedCompressed implements CoverageTransformer {

@Override
public CoverageDetailed transformJacocoObject(ExecutionDataStore executionDataStore, List<String> classesDirectory) {

CoverageInformation covered = new CoverageInformation();

final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionDataStore, coverageBuilder);
try {
for (ExecutionData executionData : executionDataStore.getContents()) {
analyzer.analyzeClass(
CoverageCollectorDetailedCompressed.class.getClassLoader()
.getResourceAsStream(executionData.getName() + ".class"),
"./"
);
}
} catch (IOException e) {
throw new RuntimeException(e);
}

for (IClassCoverage classCoverage : coverageBuilder.getClasses()) {

if (classCoverage.getInstructionCounter().getCoveredCount() > 0) {

Map<Integer, Integer> covClass = new HashMap<>();

for (IMethodCoverage methodCoverage : classCoverage.getMethods()) {

if (!"<clinit>".equals(methodCoverage.getName())) {

for (int i = methodCoverage.getFirstLine(); i <= methodCoverage.getLastLine() + 1; i++) {
int coveredI = methodCoverage.getLine(i).getInstructionCounter().getCoveredCount();

if (coveredI > 0) {
covClass.put(i, coveredI);
}
}

}
}
CoverageFromClass l = new CoverageFromClass(classCoverage.getName(), classCoverage.getPackageName(),
classCoverage.getFirstLine(), classCoverage.getLastLine(), covClass);

covered.put(classCoverage.getName(), l);
}

}
return new CoverageDetailed(covered);
}
@Override
public CoverageDetailed transformJacocoObject(ExecutionDataStore executionDataStore, List<String> classesDirectory) {

CoverageInformation covered = new CoverageInformation();

final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionDataStore, coverageBuilder);
for (ExecutionData executionData : executionDataStore.getContents()) {
try {
analyzer.analyzeClass(
CoverageCollectorDetailedCompressed.class.getClassLoader()
.getResourceAsStream(executionData.getName() + ".class"),
"./"
);
} catch (Exception ignored) {
ignored.printStackTrace();
continue;
}
}
for (IClassCoverage classCoverage : coverageBuilder.getClasses()) {
if (classCoverage.getInstructionCounter().getCoveredCount() > 0) {
final Map<Integer, Integer> covClass = new HashMap<>();
for (IMethodCoverage methodCoverage : classCoverage.getMethods()) {
if (!"<clinit>".equals(methodCoverage.getName())) {
for (int i = methodCoverage.getFirstLine(); i <= methodCoverage.getLastLine() + 1; i++) {
int coveredI = methodCoverage.getLine(i).getInstructionCounter().getCoveredCount();
if (coveredI > 0) {
covClass.put(i, coveredI);
}
}
}
}
final CoverageFromClass l = new CoverageFromClass(classCoverage.getName(), classCoverage.getPackageName(),
classCoverage.getFirstLine(), classCoverage.getLastLine(), covClass);
covered.put(classCoverage.getName(), l);
}
}
return new CoverageDetailed(covered);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ public class ListenerUtils {
if (description.isSuite()) {
className = description.getDisplayName();
} else {
className = description.getDisplayName().split("\\(")[1].split("\\)")[0];
if (description.getDisplayName().contains("(")) {
className = description.getDisplayName().split("\\(")[1].split("\\)")[0];
} else {
className = description.getDisplayName();
}
}
}
return className;
Expand Down
30 changes: 11 additions & 19 deletions src/main/java/eu/stamp_project/testrunner/runner/JUnit5Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class JUnit5Runner {
* This method is not meant to be used directly, but rather using {@link EntryPoint}
* For the expected arguments, see {@link ParserOptions}
*/
public static void main(String []args) {
public static void main(String[] args) {
final JUnit5TestResult jUnit5TestResult = new JUnit5TestResult();
final ParserOptions options = ParserOptions.parse(args);
JUnit5Runner.run(
Expand Down Expand Up @@ -59,26 +59,18 @@ public static void run(String[] testClassNames,
AtomicInteger numberOfFailedLoadClass = new AtomicInteger();
final LauncherDiscoveryRequestBuilder requestBuilder = LauncherDiscoveryRequestBuilder.request();
if (testMethodNames.length == 0) {
if (testClassNames.length > 0) {
Arrays.asList(testClassNames).forEach(testClassName -> {
try {
final Class<?> clazz = customClassLoader.loadClass(testClassName);
requestBuilder.selectors(selectClass(clazz));
} catch (ClassNotFoundException e) {
if (numberOfFailedLoadClass.incrementAndGet() > nbFailingLoadClass) {
throw new RuntimeException(e);
}
e.printStackTrace();
Arrays.asList(testClassNames).forEach(testClassName -> {
try {
final Class<?> clazz = customClassLoader.loadClass(testClassName);
requestBuilder.selectors(selectClass(clazz));
} catch (ClassNotFoundException e) {
if (numberOfFailedLoadClass.incrementAndGet() > nbFailingLoadClass) {
throw new RuntimeException(e);
}
e.printStackTrace();
}
);
} else {
try {
requestBuilder.selectors(selectClass(customClassLoader.loadClass(testClassNames[0])));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
);
} else {
Arrays.asList(testMethodNames).forEach(testMethodName -> {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import eu.stamp_project.testrunner.listener.junit4.OnlineCoveredTestResultsPerJUnit4TestMethod;
import eu.stamp_project.testrunner.runner.JUnit4Runner;
import eu.stamp_project.testrunner.runner.ParserOptions;
import eu.stamp_project.testrunner.utils.ConstantsHelper;

import java.util.Collections;
import java.util.List;
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
109 changes: 109 additions & 0 deletions src/test/java/eu/stamp_project/testrunner/EntryPointJUnit3Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package eu.stamp_project.testrunner;

import eu.stamp_project.testrunner.listener.TestResult;
import eu.stamp_project.testrunner.runner.ParserOptions;
import eu.stamp_project.testrunner.utils.ConstantsHelper;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

import static org.junit.Assert.*;

/**
* Created by Benjamin DANGLOT
* [email protected]
* on 19/02/2022
*/
public class EntryPointJUnit3Test {

public static String MAVEN_HOME;

public static String JUNIT_3_CP;

{
final String pathLocationJUnit = Test.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath();
MAVEN_HOME = pathLocationJUnit.substring(0, pathLocationJUnit.indexOf("/.m2/repository/") + "/.m2/repository/".length());
JUNIT_3_CP = MAVEN_HOME + "junit/junit/3.8.2/junit-3.8.2.jar";
}

@Test
public void testOnJUnit3() throws TimeoutException, IOException {
// make sure you run this from Java 8 otherwise the classloader is not the expected one
EntryPoint.verbose = true;
// create folders
final String ROOT_TEST_PROJECTS_JUNIT3 = "src/test/resources/test-projects-junit3/";
final File target = new File(ROOT_TEST_PROJECTS_JUNIT3 + "target");
if (target.exists()) {
FileUtils.forceDelete(target);
}
target.mkdir();
final File classes = new File(ROOT_TEST_PROJECTS_JUNIT3 + "target/classes");
classes.mkdir();
final File testClasses = new File(ROOT_TEST_PROJECTS_JUNIT3 + "target/test-classes");
testClasses.mkdir();
String command;

// compiling with spoon
Launcher l = new Launcher();
l.setBinaryOutputDirectory(ROOT_TEST_PROJECTS_JUNIT3 + "target/classes/");
l.addInputResource(ROOT_TEST_PROJECTS_JUNIT3 + "src/main/java/example/Example.java");
l.getEnvironment().setShouldCompile(true);
l.run(); // compile code;

// now we compile the test code
l = new Launcher();
l.setBinaryOutputDirectory(ROOT_TEST_PROJECTS_JUNIT3 + "target/test-classes/");
l.getEnvironment().setShouldCompile(true);
List<String> classpath = new ArrayList<>();
classpath.add(ROOT_TEST_PROJECTS_JUNIT3 + "target/classes/");
classpath.addAll(Arrays.asList(JUNIT_3_CP.split(ConstantsHelper.PATH_SEPARATOR)));
l.getEnvironment().setSourceClasspath(classpath.toArray(new String[0]));
l.addInputResource(ROOT_TEST_PROJECTS_JUNIT3 + "src/test/java/example/TestSuiteExample.java");
l.run(); // compile tests

final TestResult testResult = EntryPoint.runTests(
JUNIT_3_CP + ConstantsHelper.PATH_SEPARATOR +
ROOT_TEST_PROJECTS_JUNIT3 + "target/classes" + ConstantsHelper.PATH_SEPARATOR +
ROOT_TEST_PROJECTS_JUNIT3 + "target/test-classes",
"example.TestSuiteExample"
);
assertEquals(6, testResult.getRunningTests().size());
assertEquals(6, testResult.getPassingTests().size());
assertEquals(0, testResult.getFailingTests().size());
}

// depends on the compiler and compiler version that is used on the test project
public static final int NUMBER_OF_INSTRUCTIONS = 104;

@Before
public void setUp() {
EntryPoint.persistence = true;
EntryPoint.outPrintStream = null;
EntryPoint.errPrintStream = null;
EntryPoint.verbose = true;
EntryPoint.setMutationEngine(ConstantsHelper.MutationEngine.DESCARTES);
EntryPoint.coverageDetail = ParserOptions.CoverageTransformerDetail.SUMMARIZED;
}

@After
public void tearDown() {
EntryPoint.blackList.clear();
}

}
Loading

0 comments on commit 922bc6a

Please sign in to comment.