Added configuration options similar to the JaCoCo CLI

This commit is contained in:
Erik C. Thauvin 2023-05-01 00:09:42 -07:00
parent 57b0fa5b55
commit 224c5e6616
3 changed files with 121 additions and 39 deletions

View file

@ -42,10 +42,10 @@ public class JacocoReportOperationBuild extends Project {
var jacocoVersion = new VersionNumber(0, 8, 10); var jacocoVersion = new VersionNumber(0, 8, 10);
scope(compile) scope(compile)
.include(dependency("org.jacoco", "jacoco", jacocoVersion)) .include(dependency("org.jacoco", "jacoco", jacocoVersion).exclude("*", "org.jacoco.doc"))
.include(dependency("com.uwyn.rife2", "rife2", version(1, 6, 1))); .include(dependency("com.uwyn.rife2", "rife2", version(1, 6, 1)));
scope(runtime) scope(runtime)
.include(dependency("org.jacoco", "jacoco", jacocoVersion)); .include(dependency("org.jacoco", "jacoco", jacocoVersion).exclude("*", "org.jacoco.doc"));
scope(test) scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 9, 2))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 9, 2)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 9, 2))) .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 9, 2)))

View file

@ -16,16 +16,27 @@
package rife.bld.extension; package rife.bld.extension;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.*;
import org.jacoco.report.csv.CSVFormatter;
import org.jacoco.report.html.HTMLFormatter;
import org.jacoco.report.xml.XMLFormatter;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.operations.AbstractOperation; import rife.bld.operations.AbstractOperation;
import rife.tools.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern;
/** /**
* Generates <a href="https://www.jacoco.org/jacoco">JaCoCo</a> reports. * Generates <a href="https://www.jacoco.org/jacoco">JaCoCo</a> reports.
@ -41,16 +52,26 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
private File csv; private File csv;
private String encoding; private String encoding;
private File html; private File html;
private String name; private String name = "JaCoCo Coverage Report";
private BaseProject project; private BaseProject project;
private boolean quiet = false; private boolean quiet;
private int tabWidth = 4; private int tabWidth = 4;
private File xml; private File xml;
private IBundleCoverage analyze(ExecutionDataStore data) throws IOException {
var builder = new CoverageBuilder();
var analyzer = new Analyzer(data, builder);
for (var f : classFiles) {
LOGGER.info(f.getAbsolutePath());
analyzer.analyzeAll(f);
}
return builder.getBundle(name);
}
/** /**
* Set the locations of Java class files. * Set the locations of Java class files.
**/ **/
public JacocoReportOperation classFiles(ArrayList<File> classFiles) { public JacocoReportOperation classFiles(List<File> classFiles) {
this.classFiles.addAll(classFiles); this.classFiles.addAll(classFiles);
return this; return this;
} }
@ -74,7 +95,7 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
/** /**
* Sets a list of JaCoCo *.exec files to read. * Sets a list of JaCoCo *.exec files to read.
**/ **/
public JacocoReportOperation execFiles(ArrayList<File> execFiles) { public JacocoReportOperation execFiles(List<File> execFiles) {
this.execFiles.addAll(execFiles); this.execFiles.addAll(execFiles);
return this; return this;
} }
@ -92,27 +113,37 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
LOGGER.severe("A project must be specified."); LOGGER.severe("A project must be specified.");
} else { } else {
if (execFiles.isEmpty()) { var buildJacocoReportsDir = Path.of(project.buildDirectory().getPath(), "reports", "jacoco", "test").toFile();
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("No execution data files provided.");
}
}
if (sourceFiles.isEmpty()) { if (sourceFiles.isEmpty()) {
sourceFiles.addAll(project.mainSourceFiles()); sourceFiles.add(project.srcDirectory());
sourceFiles.addAll(project.testSourceFiles()); //sourceFiles.add(project.srcTestDirectory());
} }
if (classFiles.isEmpty()) { if (classFiles.isEmpty()) {
classFiles.addAll(getClassFiles(project.buildMainDirectory())); classFiles.add(project.buildMainDirectory());
classFiles.addAll(getClassFiles(project.buildTestDirectory())); classFiles.add(project.buildTestDirectory());
}
}
} }
private List<File> getClassFiles(File directory) { if (html == null) {
return FileUtils.getFileList(directory, Pattern.compile("^.*\\.class$"), null) html = new File(buildJacocoReportsDir, "html");
.stream().map(f -> new File(directory, f)).toList(); }
if (xml == null) {
xml = new File(buildJacocoReportsDir, "jacocoTestReport.xml");
}
if (csv == null) {
csv = new File(buildJacocoReportsDir, "jacocoTestReport.csv");
}
//noinspection ResultOfMethodCallIgnored
buildJacocoReportsDir.mkdirs();
var loader = loadExecFiles();
var bundle = analyze(loader.getExecutionDataStore());
writeReports(bundle, loader);
}
} }
/** /**
@ -123,10 +154,6 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return this; return this;
} }
public String getMessage() {
return "Hello World!";
}
/** /**
* Sets the location of the HTML report. * Sets the location of the HTML report.
*/ */
@ -135,6 +162,22 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return this; return this;
} }
private ExecFileLoader loadExecFiles() throws IOException {
var loader = new ExecFileLoader();
if (execFiles.isEmpty() && LOGGER.isLoggable(Level.WARNING) && !quiet) {
LOGGER.warning("No execution data files provided.");
} else {
for (var f : execFiles) {
if (LOGGER.isLoggable(Level.INFO) && !quiet) {
LOGGER.log(Level.INFO, "Loading execution data file: {0}",
f.getAbsolutePath());
}
loader.load(f);
}
}
return loader;
}
/** /**
* Sets the name used for the report. * Sets the name used for the report.
*/ */
@ -151,22 +194,65 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
return this; return this;
} }
private IReportVisitor reportVisitor() throws IOException {
List<IReportVisitor> visitors = new ArrayList<>();
if (xml != null) {
var formatter = new XMLFormatter();
visitors.add(formatter.createVisitor(Files.newOutputStream(xml.toPath())));
}
if (csv != null) {
var formatter = new CSVFormatter();
visitors.add(formatter.createVisitor(Files.newOutputStream(csv.toPath())));
}
if (html != null) {
var formatter = new HTMLFormatter();
visitors.add(formatter.createVisitor(new FileMultiReportOutput(html)));
}
return new MultiReportVisitor(visitors);
}
/** /**
* Sets the locations of the source files. * Sets the locations of the source files.
**/ **/
public JacocoReportOperation sourceFiles(ArrayList<File> sourceFiles) { public JacocoReportOperation sourceFiles(List<File> sourceFiles) {
this.sourceFiles.addAll(sourceFiles); this.sourceFiles.addAll(sourceFiles);
return this; return this;
} }
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private ISourceFileLocator sourceLocator() {
var multi = new MultiSourceFileLocator(tabWidth);
for (var f : sourceFiles) {
multi.add(new DirectorySourceFileLocator(f, encoding, tabWidth));
}
return multi;
}
/** /**
* Sets the tab stop width for the source pages. Default is {@code 4}. * Sets the tab stop width for the source pages. Default is {@code 4}.
*/ */
public JacocoReportOperation tabWidth(int tabWitdh) { public JacocoReportOperation tabWidth(int tabWidth) {
this.tabWidth = tabWitdh; this.tabWidth = tabWidth;
return this; return this;
} }
private void writeReports(IBundleCoverage bundle, ExecFileLoader loader)
throws IOException {
if (LOGGER.isLoggable(Level.INFO) && !quiet) {
LOGGER.log(Level.INFO, "Analyzing {0} classes.",
bundle.getClassCounter().getTotalCount());
}
IReportVisitor visitor = reportVisitor();
visitor.visitInfo(loader.getSessionInfoStore().getInfos(),
loader.getExecutionDataStore().getContents());
visitor.visitBundle(bundle, sourceLocator());
visitor.visitEnd();
}
/** /**
* Sets the location of the XML report. * Sets the location of the XML report.
*/ */
@ -174,4 +260,5 @@ public class JacocoReportOperation extends AbstractOperation<JacocoReportOperati
this.xml = xml; this.xml = xml;
return this; return this;
} }
} }

View file

@ -16,16 +16,11 @@
package rife.bld.extension; package rife.bld.extension;
public class JacocoReportOperationTest { import org.junit.jupiter.api.Test;
void verifyHello() {
if (!"Hello World!".equals(new JacocoReportOperation().getMessage())) { class JacocoReportOperationTest {
throw new AssertionError(); @Test
} else { void executeTest() {
System.out.println("Succeeded");
}
}
public static void main(String[] args) {
new JacocoReportOperationTest().verifyHello();
} }
} }