Skip to content

Commit

Permalink
add option to set detail of coverage information + method level instr…
Browse files Browse the repository at this point in the history
…uction coverage
  • Loading branch information
lacinoire committed Mar 19, 2021
1 parent 35b61aa commit c5cc0fb
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 47 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Spoon files
spooned/

# Config files
.idea/
test-runner.iml
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/eu/stamp_project/testrunner/EntryPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
* This class has options accessible from the outside:
* </p>
* <ul>
* <li>jUnit5Mode: switches from JUnit 4 to the JUnit 5 test runner</li>
* <li>verbose: boolean to enable traces to track the progress</li>
* <li>timeoutInMs: integer timeout time in milliseconds for the whole requested
* process.</li>
Expand All @@ -75,6 +76,8 @@
* stream</li>
* <li>persistence: if enable, keeps the configuration between runs, else reset
* it</li>
* <li>blackList: allows to blacklist specific test methods of a test class/li>
* <li>coverageDetail: the level of detail in which coverage should be reported</li>
* </ul>
*/
public class EntryPoint {
Expand Down Expand Up @@ -139,6 +142,12 @@ public class EntryPoint {
*/
public static List<String> blackList = new ArrayList<>();

/**
* Allows to set the level of detail at which coverage information should be reported.
* see {@link ParserOptions.CoverageTransformerDetail}
*/
public static ParserOptions.CoverageTransformerDetail coverageDetail =
ParserOptions.CoverageTransformerDetail.SUMMARIZED;

// PIT OPTIONS

Expand Down Expand Up @@ -305,6 +314,9 @@ public static Coverage runCoverage(String classpath, String targetProjectClasses
EntryPoint.blackList.isEmpty() ? "" :
(ParserOptions.FLAG_blackList + ConstantsHelper.WHITE_SPACE
+ String.join(ConstantsHelper.PATH_SEPARATOR, EntryPoint.blackList)),
EntryPoint.coverageDetail == ParserOptions.CoverageTransformerDetail.SUMMARIZED ? "" :
(ParserOptions.FLAG_coverage_detail + ConstantsHelper.WHITE_SPACE
+ EntryPoint.coverageDetail.name()),
});
return EntryPoint.runCoverage(javaCommand);
}
Expand Down Expand Up @@ -390,6 +402,9 @@ public static CoveragePerTestMethod runCoveragePerTestMethods(String classpath,
EntryPoint.blackList.isEmpty() ? ""
: (ParserOptions.FLAG_blackList + ConstantsHelper.WHITE_SPACE
+ String.join(ConstantsHelper.PATH_SEPARATOR, EntryPoint.blackList)),
EntryPoint.coverageDetail == ParserOptions.CoverageTransformerDetail.SUMMARIZED ? "" :
(ParserOptions.FLAG_coverage_detail + ConstantsHelper.WHITE_SPACE
+ EntryPoint.coverageDetail.name()),
});
try {
EntryPoint.runGivenCommandLine(javaCommand);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package eu.stamp_project.testrunner.listener.impl;

import eu.stamp_project.testrunner.listener.Coverage;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import org.jacoco.core.analysis.*;
import org.jacoco.core.data.ExecutionDataStore;

import java.io.*;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class CoverageCollectorMethodDetailed implements CoverageTransformer {
@Override
public Coverage transformJacocoObject(ExecutionDataStore executionData, String classesDirectory) {
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
try {
analyzer.analyzeAll(new File(classesDirectory));
} catch (IOException e) {
throw new RuntimeException(e);
}
final int[] counter = new int[2];
final StringBuilder builderExecutionPath = new StringBuilder();
coverageBuilder.getClasses().forEach(coverage -> {
final List<Integer> listOfCountForCounterFunction =
CoverageImpl.getListOfCountForCounterFunction(coverage, ICounter::getCoveredCount);
builderExecutionPath.append(coverage.getName())
.append(":")
.append(getCoverageInformationPerMethod(coverage, ICounter::getCoveredCount))
.append("-");
counter[0] += listOfCountForCounterFunction.stream()
.mapToInt(Integer::intValue)
.sum();
counter[1] += CoverageImpl.getListOfCountForCounterFunction(coverage, ICounter::getTotalCount)
.stream()
.mapToInt(Integer::intValue)
.sum();
});

Coverage coverage = new CoverageImpl( counter[0], counter[1],builderExecutionPath.toString());
return coverage;
}

public static String getCoverageInformationPerMethod(IClassCoverage coverage,
Function<ICounter, Integer> counterGetter) {
StringBuilder builder = new StringBuilder();
coverage.getMethods()
.stream()
.filter(iMethodCoverage -> !"<clinit>".equals(iMethodCoverage.getName()))
.forEach(iMethodCoverage -> {
builder.append(iMethodCoverage.getName()).append("+");
builder.append(iMethodCoverage.getDesc()).append("+");
builder.append(IntStream.range(iMethodCoverage.getFirstLine(), iMethodCoverage.getLastLine() + 1)
.mapToObj(iMethodCoverage::getLine)
.map(ILine::getInstructionCounter)
.map(counterGetter)
.map(Object::toString)
.collect(Collectors.joining(",")));
builder.append("|");
});
if (builder.length() > 0) {
builder.replace(builder.length()-1, builder.length(),"");
}
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,4 @@ public Coverage transformJacocoObject(ExecutionDataStore executionData, String c
return coverage;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import eu.stamp_project.testrunner.listener.Coverage;
import eu.stamp_project.testrunner.listener.CoveragePerTestMethod;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.TestResult;
import eu.stamp_project.testrunner.runner.Loader;
import eu.stamp_project.testrunner.utils.ConstantsHelper;
Expand Down Expand Up @@ -35,15 +36,19 @@ public class CoveragePerTestMethodImpl implements CoveragePerTestMethod {

protected transient SessionInfoStore sessionInfos;

protected transient CoverageTransformer coverageTransformer;

public CoveragePerTestMethodImpl() {
coverageResultsMap = null;
classesDirectory = null;
this.coverageTransformer = new CoverageCollectorSummarization();
}

public CoveragePerTestMethodImpl(RuntimeData data, String classesDirectory) {
public CoveragePerTestMethodImpl(RuntimeData data, String classesDirectory, CoverageTransformer coverageTransformer) {
this.data = data;
this.classesDirectory = classesDirectory;
this.coverageResultsMap = new HashMap<>();
this.coverageTransformer = coverageTransformer;
}

public String getClassesDirectory() {
Expand All @@ -62,6 +67,10 @@ public SessionInfoStore getSessionInfos() {
return sessionInfos;
}

public CoverageTransformer getCoverageTransformer() {
return coverageTransformer;
}

public void setData(RuntimeData data) {
this.data = data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import eu.stamp_project.testrunner.listener.Coverage;
import eu.stamp_project.testrunner.listener.CoveragePerTestMethod;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.impl.CoverageCollectorSummarization;
import eu.stamp_project.testrunner.listener.impl.CoverageImpl;
import eu.stamp_project.testrunner.listener.impl.CoveragePerTestMethodImpl;
Expand Down Expand Up @@ -43,8 +44,8 @@ public class CoveragePerJUnit4TestMethod extends JUnit4TestResult implements Cov
*/
private Map<String, List<IClassCoverage>> coveragesPerMethodName;

public CoveragePerJUnit4TestMethod(RuntimeData data, String classesDirectory) {
this.internalCoverage = new CoveragePerTestMethodImpl(data, classesDirectory);
public CoveragePerJUnit4TestMethod(RuntimeData data, String classesDirectory, CoverageTransformer coverageTransformer) {
this.internalCoverage = new CoveragePerTestMethodImpl(data, classesDirectory, coverageTransformer);
this.coveragesPerMethodName = new HashMap<>();
}

Expand Down Expand Up @@ -73,8 +74,10 @@ public synchronized void testFinished(Description description) throws Exception
this.internalCoverage.getSessionInfos(),
false
);
CoverageCollectorSummarization coverageBilder = new CoverageCollectorSummarization();
Coverage jUnit4Coverage = coverageBilder.transformJacocoObject(this.internalCoverage.getExecutionData(), this.internalCoverage.getClassesDirectory());

Coverage jUnit4Coverage =
internalCoverage.getCoverageTransformer().transformJacocoObject(this.internalCoverage.getExecutionData(),
this.internalCoverage.getClassesDirectory());
this.internalCoverage.getCoverageResultsMap().put(description.getMethodName(), jUnit4Coverage);
if (isParametrized.test(description.getMethodName())) {
this.collectForParametrizedTest(fromParametrizedToSimpleName.apply(description.getMethodName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import eu.stamp_project.testrunner.listener.Coverage;
import eu.stamp_project.testrunner.listener.CoveragePerTestMethod;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.impl.CoverageCollectorSummarization;
import eu.stamp_project.testrunner.listener.impl.CoveragePerTestMethodImpl;
import eu.stamp_project.testrunner.runner.Failure;
Expand All @@ -27,8 +28,8 @@ public class CoveragePerJUnit5TestMethod extends JUnit5TestResult implements Cov
private CoveragePerTestMethodImpl internalCoverage;


public CoveragePerJUnit5TestMethod(RuntimeData data, String classesDirectory) {
this.internalCoverage = new CoveragePerTestMethodImpl(data, classesDirectory);
public CoveragePerJUnit5TestMethod(RuntimeData data, String classesDirectory, CoverageTransformer coverageTransformer) {
this.internalCoverage = new CoveragePerTestMethodImpl(data, classesDirectory, coverageTransformer);
}

@Override
Expand All @@ -54,9 +55,10 @@ public synchronized void executionFinished(TestIdentifier testIdentifier, TestEx
this.internalCoverage.getSessionInfos(),
false
);

CoverageCollectorSummarization coverageBuilder = new CoverageCollectorSummarization();
Coverage jUnit5Coverage = coverageBuilder.transformJacocoObject(this.internalCoverage.getExecutionData(), this.internalCoverage.getClassesDirectory());

Coverage jUnit5Coverage =
internalCoverage.getCoverageTransformer().transformJacocoObject(this.internalCoverage.getExecutionData(),
this.internalCoverage.getClassesDirectory());
this.internalCoverage.getCoverageResultsMap().put(this.toString.apply(testIdentifier), jUnit5Coverage);
switch (testExecutionResult.getStatus()) {
case FAILED:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package eu.stamp_project.testrunner.runner;

import eu.stamp_project.testrunner.listener.Coverage;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.impl.CoverageCollectorDetailed;
import eu.stamp_project.testrunner.listener.impl.CoverageCollectorMethodDetailed;
import eu.stamp_project.testrunner.listener.impl.CoverageCollectorSummarization;
import eu.stamp_project.testrunner.utils.ConstantsHelper;

import java.util.ArrayList;
Expand Down Expand Up @@ -37,6 +42,9 @@ public static ParserOptions parse(String[] args) {
case FLAG_blackList:
parserOptions.blackList = convertArrayToList.apply(args[++i]);
break;
case FLAG_coverage_detail:
parserOptions.coverageTransformerDetail = CoverageTransformerDetail.valueOf(args[++i]);
break;
case " ":
case "":
break;
Expand Down Expand Up @@ -64,6 +72,9 @@ private static void usage() {
usage.append(FLAG_blackList).append(ConstantsHelper.WHITE_SPACE)
.append(FLAG_HELP_blackList).append(ConstantsHelper.LINE_SEPARATOR);

usage.append(FLAG_coverage_detail).append(ConstantsHelper.WHITE_SPACE)
.append(FLAG_HELP_coverage_detail).append(ConstantsHelper.LINE_SEPARATOR);

System.out.println(usage.toString());
}

Expand Down Expand Up @@ -107,11 +118,31 @@ private static void usage() {

public static final String FLAG_HELP_blackList = "This flag must be followed by the list of simple names of test methods to NOT be run. Names must be separated by the system path separator, e.g. ':' on Linux";



public enum CoverageTransformerDetail {
SUMMARIZED,
DETAIL,
METHOD_DETAIL
}
/**
* This value represents at which level of detail coverage information should be provided
*/
private CoverageTransformerDetail coverageTransformerDetail;

public static final String FLAG_coverage_detail = "--coverage-detail";

public static final String FLAG_HELP_coverage_detail = "The value following this flag defines the level of detail" +
" provided in the coverage information. Valid values:" +
"'SUMMARIZED' (default), 'DETAIL' or 'METHOD_DETAIL'.";


private ParserOptions() {
this.pathToCompiledClassesOfTheProject = "";
this.fullQualifiedNameOfTestClassesToRun = new String[]{};
this.testMethodNamesToRun = new String[]{};
this.blackList = new ArrayList<>();
this.coverageTransformerDetail = CoverageTransformerDetail.SUMMARIZED;
}

public String getPathToCompiledClassesOfTheProject() {
Expand All @@ -130,4 +161,17 @@ public List<String> getBlackList() {
return blackList;
}

public CoverageTransformer getCoverageTransformer() {
switch (coverageTransformerDetail) {
case DETAIL:
return new CoverageCollectorDetailed();
case METHOD_DETAIL:
return new CoverageCollectorMethodDetailed();
case SUMMARIZED:
default:
return new CoverageCollectorSummarization();
}

}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eu.stamp_project.testrunner.runner.coverage;

import eu.stamp_project.testrunner.EntryPoint;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.CoveredTestResult;
import eu.stamp_project.testrunner.listener.junit4.JUnit4Coverage;
import eu.stamp_project.testrunner.listener.junit4.JUnit4TestResult;
Expand All @@ -17,12 +18,12 @@
*/
public class JUnit4JacocoRunner extends JacocoRunner {

public JUnit4JacocoRunner(String classesDirectory, String testClassesDirectory) {
super(classesDirectory, testClassesDirectory);
public JUnit4JacocoRunner(String classesDirectory, String testClassesDirectory, CoverageTransformer coverageTransformer) {
super(classesDirectory, testClassesDirectory, coverageTransformer);
}

public JUnit4JacocoRunner(String classesDirectory, String testClassesDirectory, List<String> blackList) {
super(classesDirectory, testClassesDirectory, blackList);
public JUnit4JacocoRunner(String classesDirectory, String testClassesDirectory, List<String> blackList, CoverageTransformer coverageTransformer) {
super(classesDirectory, testClassesDirectory, blackList, coverageTransformer);
}

/**
Expand All @@ -38,7 +39,8 @@ public static void main(String[] args) {
final JacocoRunner jacocoRunner =
new JUnit4JacocoRunner(classesDirectory,
testClassesDirectory,
options.getBlackList()
options.getBlackList(),
options.getCoverageTransformer()
);
final String[] testClassesToRun = options.getFullQualifiedNameOfTestClassesToRun();
if (testClassesToRun.length > 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import eu.stamp_project.testrunner.EntryPoint;
import eu.stamp_project.testrunner.listener.CoveragePerTestMethod;
import eu.stamp_project.testrunner.listener.CoverageTransformer;
import eu.stamp_project.testrunner.listener.junit4.CoveragePerJUnit4TestMethod;
import eu.stamp_project.testrunner.listener.junit4.JUnit4TestResult;
import eu.stamp_project.testrunner.runner.JUnit4Runner;
Expand All @@ -19,16 +20,16 @@
*/
public class JUnit4JacocoRunnerPerTestMethod extends JacocoRunnerPerTestMethod {

public JUnit4JacocoRunnerPerTestMethod(String classesDirectory, String testClassesDirectory, List<String> blackList) {
super(classesDirectory, testClassesDirectory, blackList);
public JUnit4JacocoRunnerPerTestMethod(String classesDirectory, String testClassesDirectory, List<String> blackList, CoverageTransformer coverageTransformer) {
super(classesDirectory, testClassesDirectory, blackList, coverageTransformer);
}

@Override
protected CoveragePerTestMethod executeTestPerTestMethod(RuntimeData data,
String classesDirectory,
String[] testClassNames,
String[] testMethodNames) {
final CoveragePerTestMethod listener = new CoveragePerJUnit4TestMethod(data, classesDirectory);
final CoveragePerTestMethod listener = new CoveragePerJUnit4TestMethod(data, classesDirectory, coverageTransformer);
JUnit4Runner.run(
testClassNames,
testMethodNames,
Expand All @@ -52,7 +53,8 @@ public static void main(String[] args) {
new JUnit4JacocoRunnerPerTestMethod(
classesDirectory,
testClassesDirectory,
options.getBlackList()
options.getBlackList(),
options.getCoverageTransformer()
).runCoveragePerTestMethod(classesDirectory,
testClassesDirectory,
options.getFullQualifiedNameOfTestClassesToRun()[0],
Expand Down
Loading

0 comments on commit c5cc0fb

Please sign in to comment.