diff --git a/apache-rat-core/pom.xml b/apache-rat-core/pom.xml
index 21f0c583c..061670044 100644
--- a/apache-rat-core/pom.xml
+++ b/apache-rat-core/pom.xml
@@ -263,5 +263,10 @@
jimfstest
+
+ org.xmlunit
+ xmlunit-assertj3
+ test
+
diff --git a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy
index 226394df0..0a46a22f9 100644
--- a/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy
+++ b/apache-rat-core/src/it/resources/ReportTest/RAT_14/verify.groovy
@@ -68,7 +68,8 @@ ReportConfiguration configuration = OptionCollection.parseCommands(src, myArgs,
assertNotNull(configuration)
configuration.validate(DefaultLog.getInstance().&error)
Reporter reporter = new Reporter(configuration)
-ClaimStatistic statistic = reporter.execute()
+Reporter.Output output = reporter.execute()
+ClaimStatistic statistic = output.getStatistic()
assertEquals(3, statistic.getCounter(ClaimStatistic.Counter.APPROVED))
assertEquals(2, statistic.getCounter(ClaimStatistic.Counter.ARCHIVES))
diff --git a/apache-rat-core/src/main/java/org/apache/rat/Report.java b/apache-rat-core/src/main/java/org/apache/rat/Report.java
index 5f5f4cb35..4346951d2 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/Report.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/Report.java
@@ -51,22 +51,22 @@ public static void main(final String[] args) throws Exception {
ReportConfiguration configuration = OptionCollection.parseCommands(new File("."), args, Report::printUsage);
if (configuration != null) {
configuration.validate(DefaultLog.getInstance()::error);
- Reporter reporter = new Reporter(configuration);
- reporter.output();
- reporter.writeSummary(DefaultLog.getInstance().asWriter());
+ Reporter.Output output = new Reporter(configuration).execute();
+ output.format(configuration);
+ output.writeSummary(DefaultLog.getInstance().asWriter());
if (configuration.getClaimValidator().hasErrors()) {
- configuration.getClaimValidator().logIssues(reporter.getClaimsStatistic());
+ configuration.getClaimValidator().logIssues(output.getStatistic());
throw new RatDocumentAnalysisException(format("Issues with %s",
String.join(", ",
- configuration.getClaimValidator().listIssues(reporter.getClaimsStatistic()))));
+ configuration.getClaimValidator().listIssues(output.getStatistic()))));
}
}
}
/**
* Prints the usage message on {@code System.out}.
- * @param opts The defined options.
+ * @param opts the defined options.
*/
private static void printUsage(final Options opts) {
new Help(System.out).printUsage(opts);
diff --git a/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java b/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
index 579095824..a17077e8c 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/ReportConfiguration.java
@@ -35,19 +35,24 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.SortedSet;
import java.util.function.Consumer;
+import java.util.stream.Stream;
import org.apache.commons.collections4.set.UnmodifiableSortedSet;
import org.apache.commons.io.function.IOSupplier;
import org.apache.commons.io.output.CloseShieldOutputStream;
+import org.apache.commons.lang3.StringUtils;
import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
import org.apache.rat.commandline.StyleSheets;
import org.apache.rat.config.AddLicenseHeaders;
import org.apache.rat.config.exclusion.ExclusionProcessor;
import org.apache.rat.config.exclusion.StandardCollection;
import org.apache.rat.config.results.ClaimValidator;
+import org.apache.rat.configuration.XMLConfigurationReader;
import org.apache.rat.configuration.builders.AnyBuilder;
import org.apache.rat.document.DocumentName;
import org.apache.rat.document.DocumentNameMatcher;
@@ -56,12 +61,20 @@
import org.apache.rat.license.ILicenseFamily;
import org.apache.rat.license.LicenseSetFactory;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.RatReport;
import org.apache.rat.report.Reportable;
+import org.apache.rat.report.claim.ClaimStatistic;
+import org.apache.rat.report.xml.writer.XmlWriter;
import org.apache.rat.utils.DefaultLog;
import org.apache.rat.utils.Log.Level;
import org.apache.rat.utils.ReportingSet;
+import org.apache.rat.utils.StandardXmlFactory;
import org.apache.rat.walker.FileListWalker;
import org.apache.rat.walker.ReportableListWalker;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* A configuration object is used by the front end to invoke the
@@ -87,7 +100,7 @@ public enum Processing {
ABSENCE("List licenses found and any unknown licences");
/**
- * Description of the processing
+ * Description of the processing.
*/
private final String description;
@@ -111,19 +124,23 @@ public String desc() {
* {@code true} if we are adding license headers to the files.
*/
private boolean addingLicenses;
+
/**
* {@code true} if we are adding license headers in place (no *.new files)
*/
private boolean addingLicensesForced;
+
/**
* The copyright message to add if we are adding headers. Will be {@code null}
* if we are not adding copyright messages.
*/
private String copyrightMessage;
+
/**
* The IODescriptor that provides the output stream to write the report to.
*/
private IODescriptor out;
+
/**
* The IODescriptor that provides the stylesheet to style the XML output.
*/
@@ -140,7 +157,7 @@ public String desc() {
private final List reportables;
/**
- * A predicate to test if a path should be included in the processing.
+ * The exclusion processor that determines if a file is included or excluded.
*/
private final ExclusionProcessor exclusionProcessor;
@@ -148,22 +165,27 @@ public String desc() {
* The default filter for displaying families.
*/
private LicenseFilter listFamilies;
+
/**
* The default filter for displaying licenses.
*/
private LicenseFilter listLicenses;
+
/**
* {@code true} if this is a dry run and no processing is to take place.
*/
private boolean dryRun;
+
/**
* How to process ARCHIVE document types.
*/
private Processing archiveProcessing;
+
/**
* How to process STANDARD document types.
*/
private Processing standardProcessing;
+
/**
* The ClaimValidator to validate min/max counts and similar claims.
*/
@@ -183,6 +205,10 @@ public ReportConfiguration() {
reportables = new ArrayList<>();
}
+ public SerDes serDes() {
+ return new SerDes();
+ }
+
/**
* Report the excluded files to the appendable object.
* @param appendable the appendable object to write to.
@@ -242,6 +268,16 @@ public ReportableListWalker.Builder getSources() {
return builder;
}
+ // for testing access
+ Iterable sources() {
+ return sources;
+ }
+
+ // for testing access
+ Stream reportables() {
+ return reportables.stream().map(Reportable::name);
+ }
+
/**
* Gets the matcher that matches generated text.
* @return the matcher that matches generated text.
@@ -267,16 +303,16 @@ public void setArchiveProcessing(final Processing archiveProcessing) {
}
/**
- * Retrieves the archive processing type.
- * @return the archive processing type.
+ * Retrieves the standard processing type.
+ * @return the standard processing type.
*/
public Processing getStandardProcessing() {
return standardProcessing == null ? Defaults.STANDARD_PROCESSING : standardProcessing;
}
/**
- * Sets the archive processing type. If not set will default to NOTIFICATION.
- * @param standardProcessing the type of processing archives should have.
+ * Sets the standard processing type. If not set will default to NOTIFICATION.
+ * @param standardProcessing the type of processing standard files should have.
*/
public void setStandardProcessing(final Processing standardProcessing) {
this.standardProcessing = standardProcessing;
@@ -309,7 +345,7 @@ public void logLicenseCollisions(final Level level) {
/**
* Sets the reporting option for duplicate licenses.
- * @param state the ReportingSt.Option to use for reporting.
+ * @param state the ReportingSet.Option to use for reporting.
*/
public void licenseDuplicateOption(final ReportingSet.Options state) {
licenseSetFactory.licenseDuplicateOption(state);
@@ -424,6 +460,14 @@ public void addIncludedFilter(final FileFilter fileFilter) {
exclusionProcessor.addIncludedMatcher(new DocumentNameMatcher(fileFilter));
}
+ /**
+ * Includes files that match a DocumentNameMatcher.
+ * @param matcher the DocumentNameMatcher to match.
+ */
+ public void addIncludedMatcher(final DocumentNameMatcher matcher) {
+ exclusionProcessor.addIncludedMatcher(matcher);
+ }
+
/**
* Add file patterns that are to be included. These patterns override any exclusion of
* the same files.
@@ -442,6 +486,11 @@ public DocumentNameMatcher getDocumentExcluder(final DocumentName baseDir) {
return exclusionProcessor.getNameMatcher(baseDir);
}
+ // visible for testing.
+ ExclusionProcessor getExclusionProcessor() {
+ return exclusionProcessor;
+ }
+
/**
* Gets the IOSupplier with the style sheet.
* @return the Supplier of the InputStream that is the XSLT style sheet to style
@@ -523,7 +572,7 @@ public void setStyleSheet(final URL styleSheet) {
* appended to and that can be closed. If an {@code OutputStream} should not be
* closed consider wrapping it in a {@code CloseShieldOutputStream}
* @param out the OutputStream supplier that provides the output stream to write
- * the report to. A null value will use System.out.
+ * the report to. A {@code null} value will use {@code System.out}.
* @see CloseShieldOutputStream
*/
public void setOut(final IODescriptor out) {
@@ -546,6 +595,7 @@ public void setOut(final File file) {
DefaultLog.getInstance().warn("Unable to delete file: " + file);
}
}
+
File parent = file.getParentFile();
if (!parent.mkdirs() && !parent.isDirectory()) {
DefaultLog.getInstance().warn("Unable to create directory: " + file.getParentFile());
@@ -645,7 +695,7 @@ public void addApprovedLicenseCategory(final ILicenseFamily approvedILicenseFami
}
/**
- * Adds a license family category (id) to the list of approved licenses
+ * Adds a license family category (id) to the list of approved licenses.
* @param familyCategory the category to add.
*/
public void addApprovedLicenseCategory(final String familyCategory) {
@@ -827,8 +877,8 @@ public void setAddLicenseHeaders(final AddLicenseHeaders addLicenseHeaders) {
*
{@code approved} - Only approved license families will be returned.
*
{@code none} - No license families will be returned.
*
- * @param filter The license filter.
- * @return The set of defined licenses.
+ * @param filter the license filter.
+ * @return the set of defined licenses.
*/
public SortedSet getLicenseFamilies(final LicenseFilter filter) {
return licenseSetFactory.getLicenseFamilies(filter);
@@ -871,7 +921,7 @@ public void validate(final Consumer logger) {
/**
* An IODescriptor comprises a name and an IOSupplier. The name should identify the contents of the stream.
* @param name the name of the supplier.
- * @param ioSupplier the IOSupplier that provides either an InputStream or an OutputStream
+ * @param ioSupplier the IOSupplier that provides either an InputStream or an OutputStream.
* @param either InputStream or OutputStream.
*/
public record IODescriptor(String name, IOSupplier ioSupplier) {
@@ -907,4 +957,131 @@ static IODescriptor input(final File file) {
return new IODescriptor<>(file.toString(), () -> new FileInputStream(file));
}
}
+
+ /**
+ * Serializes the ReportConfiguration into an XML document that can be deserialized by the Serde.
+ * Deserialized ReportConfigurations can not be executed as the reportable objects use named placeholders
+ * and do not have access to the original object.
+ */
+ @SuppressFBWarnings("EI_EXPOSE_REP2")
+ public class SerDes {
+ /**
+ * Writes the configuration as an XML document to the appendable.
+ *
+ * @param appendable the Appendable to write to.
+ * @throws IOException on error.
+ */
+ public void serialize(final Appendable appendable) throws IOException {
+ try (XmlWriter writer = new XmlWriter(appendable)) {
+ writer.startElement("ReportConfiguration")
+ .attribute("addingLicenses", Boolean.toString(addingLicenses))
+ .attribute("addingLicensesForced", Boolean.toString(addingLicensesForced))
+ .attribute("listFamilies", listFamilies.name())
+ .attribute("listLicenses", listLicenses.name())
+ .attribute("dryRun", Boolean.toString(dryRun))
+ .attribute("archiveProcessing", getArchiveProcessing().name())
+ .attribute("standardProcessing", getStandardProcessing().name())
+ .attribute("stylesheet", styleSheet.name())
+ .attribute("output", out.name());
+ if (StringUtils.isNotEmpty(copyrightMessage)) {
+ writer.startElement("copyrightMessage").content(copyrightMessage).closeElement();
+ }
+ writer.startElement("sources");
+ for (File f : sources) {
+ writer.startElement("source").attribute("name", f.toString()).closeElement();
+ }
+ writer.closeElement("sources").startElement("reportables");
+ for (Reportable reportable : reportables) {
+ writer.startElement("reportable")
+ .attribute("baseName", reportable.name().getBaseName())
+ .attribute("name", reportable.name().toString())
+ .attribute("class", reportable.getClass().getName()).closeElement();
+ }
+ writer.closeElement();
+
+ exclusionProcessor.serDes().serialize(writer);
+
+ writer.startElement("claimValidator");
+ for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) {
+ writer.startElement("claimCounter")
+ .attribute("name", counter.name()).attribute("min", Integer.toString(claimValidator.getMin(counter)))
+ .attribute("max", Integer.toString(claimValidator.getMax(counter))).closeElement();
+ }
+ writer.closeElement();
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ public void deserialize(final IOSupplier inputStreamSupplier, final DocumentName workingDirectory) throws IOException {
+ org.w3c.dom.Document document;
+ try (InputStream stream = inputStreamSupplier.get()) {
+ document = StandardXmlFactory.documentBuilder().parse(stream);
+ } catch (SAXException e) {
+ throw new IOException("Unable to read input", e);
+ }
+ Node node = document.getDocumentElement();
+ if (!node.getNodeName().equals("ReportConfiguration")) {
+ throw new IOException("Invalid ReportConfiguration");
+ }
+ Map attributes = XMLConfigurationReader.attributes(node);
+ addingLicenses = Boolean.parseBoolean(attributes.get("addingLicenses"));
+ addingLicensesForced = Boolean.parseBoolean(attributes.get("addingLicensesForced"));
+ listFamilies = LicenseFilter.valueOf(attributes.get("listFamilies"));
+ listLicenses = LicenseFilter.valueOf(attributes.get("listLicenses"));
+ dryRun = Boolean.parseBoolean(attributes.get("dryRun"));
+ archiveProcessing = Processing.valueOf(attributes.get("archiveProcessing"));
+ standardProcessing = Processing.valueOf(attributes.get("standardProcessing"));
+ String styleName = attributes.get("stylesheet");
+ if (styleName != null) {
+ styleSheet = StyleSheets.getStyleSheet(styleName);
+ }
+ String outputName = attributes.get("output");
+ if (outputName != null) {
+ if (outputName.equals(ReportConfiguration.SYSTEM_OUT.name())) {
+ out = ReportConfiguration.SYSTEM_OUT;
+ } else {
+ out = IODescriptor.output(outputName, workingDirectory);
+ }
+ }
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("copyrightMessage"),
+ lNode -> setCopyrightMessage(lNode.getTextContent()));
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("source"), lNode -> {
+ Map nAttributes = XMLConfigurationReader.attributes(lNode);
+ addSource(new File(nAttributes.get("name")));
+ });
+
+ // Deserialize the reportables.
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("reportable"), lNode -> {
+ Map nAttributes = XMLConfigurationReader.attributes(lNode);
+ DocumentName documentName = DocumentName.builder().setBaseName(nAttributes.get("baseName"))
+ .setName(nAttributes.get("name")).build();
+ addSource(new DeserializedReportable(documentName));
+ });
+
+ exclusionProcessor.serDes().deserialize(document.getElementsByTagName("ExclusionProcessor").item(0));
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("claimCounter"), lNode -> {
+ Map nAttributes = XMLConfigurationReader.attributes(lNode);
+ ClaimStatistic.Counter counter = ClaimStatistic.Counter.valueOf(nAttributes.get("name"));
+ claimValidator.setMin(counter, Integer.parseInt(nAttributes.get("min")));
+ claimValidator.setMax(counter, Integer.parseInt(nAttributes.get("max")));
+ });
+ }
+ }
+
+ /**
+ * A record that identifies a deserialized reportable. Deserialized reportables are not executable.
+ * @param name the name of the reportable.
+ */
+ private record DeserializedReportable(DocumentName name) implements Reportable {
+ @Override
+ public void run(final RatReport report) throws RatException {
+ throw new RatException("Attempt to run a deserialized reportable");
+ }
+ }
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/Reporter.java b/apache-rat-core/src/main/java/org/apache/rat/Reporter.java
index 5cf396d9c..c752db924 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/Reporter.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/Reporter.java
@@ -18,14 +18,14 @@
*/
package org.apache.rat;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
-import java.io.Writer;
+import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import javax.xml.transform.TransformerException;
@@ -34,6 +34,7 @@
import org.apache.commons.io.function.IOSupplier;
import org.apache.rat.api.RatException;
+import org.apache.rat.document.DocumentName;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
import org.apache.rat.report.RatReport;
import org.apache.rat.report.claim.ClaimStatistic;
@@ -41,6 +42,8 @@
import org.apache.rat.report.xml.writer.XmlWriter;
import org.apache.rat.utils.StandardXmlFactory;
import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
/**
* Class that executes the report as defined in a {@link ReportConfiguration} and stores
@@ -48,18 +51,21 @@
*/
public class Reporter {
- /** Format used for listing licenses. */
+ /**
+ * Format used for listing licenses.
+ */
private static final String LICENSE_FORMAT = "%s:\t%s%n\t\t%s%n";
- /** The XML output document */
- private Document document;
-
- /** Statistics generated as the report was built */
- private ClaimStatistic statistic;
-
- /** The configuration for the report */
+ /**
+ * The configuration for the report.
+ */
private final ReportConfiguration configuration;
+ /**
+ * The output from the execution.
+ */
+ private Output output;
+
/**
* Create the reporter.
*
@@ -71,112 +77,237 @@ public Reporter(final ReportConfiguration configuration) {
/**
* Executes the report and builds the output.
- * This method will build the internal XML document if it does not already exist.
- * If this method or either of the {@link #output()} methods have already been called this method will return
- * the previous results.
- * @return the claim statistics.
+ *
+ * @return the Output object.
* @throws RatException on error.
*/
- public ClaimStatistic execute() throws RatException {
- if (document == null || statistic == null) {
- try {
- if (configuration.hasSource()) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- Writer outputWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
- try (XmlWriter writer = new XmlWriter(outputWriter)) {
- statistic = new ClaimStatistic();
- RatReport report = XmlReportFactory.createStandardReport(writer, statistic, configuration);
- report.startReport();
- configuration.getSources().build().run(report);
- report.endReport();
- }
- InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
- document = StandardXmlFactory.documentBuilder().parse(inputStream);
- } else {
- document = StandardXmlFactory.documentBuilder().newDocument();
- statistic = new ClaimStatistic();
+ public Output execute() throws RatException {
+ try {
+ Output.Builder builder = Output.builder().configuration(configuration);
+ if (configuration.hasSource()) {
+ StringBuilder sb = new StringBuilder();
+ try (XmlWriter writer = new XmlWriter(sb)) {
+ writer.startDocument();
+ ClaimStatistic statistic = new ClaimStatistic();
+ builder.statistic(statistic);
+ RatReport report = XmlReportFactory.createStandardReport(writer, statistic, configuration);
+ report.startReport();
+ configuration.getSources().build().run(report);
+ report.endReport();
+ InputSource inputSource = new InputSource(new StringReader(sb.toString()));
+ builder.document(StandardXmlFactory.documentBuilder().parse(inputSource));
}
- } catch (Exception e) {
- throw RatException.makeRatException(e);
+ } else {
+ builder.document = StandardXmlFactory.documentBuilder().newDocument();
+ builder.statistic(new ClaimStatistic());
}
+ this.output = builder.build();
+ return output;
+ } catch (Exception e) {
+ throw RatException.makeRatException(e);
}
- return statistic;
}
/**
- * Get the claim statistics from the run.
+ * Gets the output from the last {@link #execute} call or {@code null} if {@link #execute} has not been called.
*
- * @return the claim statistics.
+ * @return the output
*/
- public ClaimStatistic getClaimsStatistic() {
- return statistic;
+ public Output getOutput() {
+ return output;
}
/**
- * Outputs the report using the stylesheet and output specified in the configuration.
- * @return the Claim statistic from the run.
- * @throws RatException on error.
+ * The output from a report run.
*/
- public ClaimStatistic output() throws RatException {
- return output(configuration.getStyleSheet(), configuration.getOutput());
- }
+ public static final class Output {
+ /**
+ * The XML output document.
+ */
+ private final Document document;
+ /**
+ * The claim statics from the execution that generated the document.
+ * May be empty if the Document was read from disk.
+ */
+ private final ClaimStatistic statistic;
+ /**
+ * The configuration that generated the document.
+ */
+ private final ReportConfiguration configuration;
- /**
- * Outputs the report to the specified output using the stylesheet. It is safe to call this method more than once
- * in order to generate multiple reports from the same run.
- *
- * @param stylesheet the style sheet to use for XSLT formatting.
- * @param output the output stream to write to.
- * @return the Claim statistic for the run.
- * @throws RatException on error.
- */
- public ClaimStatistic output(final IOSupplier stylesheet, final IOSupplier output) throws RatException {
- ClaimStatistic result = execute();
- try (OutputStream out = output.get();
- InputStream styleIn = stylesheet.get()) {
- StandardXmlFactory.createTransformer(styleIn).transform(new DOMSource(document),
- new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));
- return result;
- } catch (TransformerException | IOException e) {
- throw new RatException(e);
+ /**
+ * Create an output with statistics.
+ *
+ * @param builder the Builder
+ */
+ private Output(final Builder builder) {
+ this.document = builder.document;
+ this.statistic = builder.statistic == null ? new ClaimStatistic() : builder.statistic;
+ this.configuration = builder.configuration == null ? new ReportConfiguration() : builder.configuration;
}
- }
- /**
- * Lists the licenses on the configured output stream.
- * @param configuration The configuration for the system
- * @param filter the license filter that specifies which licenses to output.
- * @throws IOException if PrintWriter can not be retrieved from configuration.
- */
- public static void listLicenses(final ReportConfiguration configuration, final LicenseFilter filter) throws IOException {
- try (PrintWriter pw = configuration.getWriter().get()) {
- pw.format("Licenses (%s):%n", filter);
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Gets the document that was generated during execution.
+ *
+ * @return the document that was generated during execution.
+ */
+ public Document getDocument() {
+ return document;
+ }
+
+ /**
+ * Get the claim statistics from the run.
+ *
+ * @return the claim statistics.
+ */
+ public ClaimStatistic getStatistic() {
+ return statistic;
+ }
+
+ public ReportConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ /**
+ * Formats the report to the output and using the stylesheet found in the report configuration.
+ *
+ * @param config the RAT report configuration.
+ * @throws RatException on error.
+ */
+ public void format(final ReportConfiguration config) throws RatException {
+ format(config.getStyleSheet(), config.getOutput());
+ }
+
+ /**
+ * Formats the report to the specified output using the stylesheet. It is safe to call this method more than once
+ * in order to generate multiple reports from the same run.
+ *
+ * @param stylesheet the style sheet to use for XSLT formatting.
+ * @param output the output stream to write to.
+ * @throws RatException on error.
+ */
+ public void format(final IOSupplier stylesheet, final IOSupplier output) throws RatException {
+ try (OutputStream out = output.get();
+ InputStream styleIn = stylesheet.get()) {
+ StandardXmlFactory.createTransformer(styleIn).transform(new DOMSource(document),
+ new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));
+ } catch (TransformerException | IOException e) {
+ throw new RatException(e);
+ }
+ }
+
+ /**
+ * Lists the licenses on the print writer.
+ *
+ * @param printWriter the print writer to write to.
+ * @param filter the license filter that specifies which licenses to output.
+ */
+ public void listLicenses(final PrintWriter printWriter, final LicenseFilter filter) {
+ printWriter.format("Licenses (%s):%n", filter);
configuration.getLicenses(filter)
- .forEach(lic -> pw.format(LICENSE_FORMAT, lic.getLicenseFamily().getFamilyCategory(),
+ .forEach(lic -> printWriter.format(LICENSE_FORMAT, lic.getLicenseFamily().getFamilyCategory(),
lic.getLicenseFamily().getFamilyName(), lic.getNote()));
- pw.println();
+ printWriter.println();
}
- }
- /**
- * Writes a text summary of issues with the run.
- * @param appendable the appendable to write to.
- * @throws IOException on error.
- */
- public void writeSummary(final Appendable appendable) throws IOException {
- appendable.append("RAT summary:").append(System.lineSeparator());
- for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) {
- appendable.append(" ").append(counter.displayName()).append(": ")
- .append(Integer.toString(getClaimsStatistic().getCounter(counter)))
- .append(System.lineSeparator());
+ /**
+ * Lists the licenses on the output specified in the configuration.
+ *
+ * @param filter the license filter that specifies which licenses to output.
+ * @throws IOException if PrintWriter can not be retrieved from configuration.
+ */
+ public void listLicenses(final LicenseFilter filter) throws IOException {
+ try (PrintWriter pw = configuration.getWriter().get()) {
+ listLicenses(pw, filter);
+ }
}
- }
- /**
- * Gets the document that was generated during execution.
- * @return the document that was generated during execution.
- */
- public Document getDocument() {
- return document;
+ /**
+ * Writes a text summary of issues with the run.
+ *
+ * @param appendable the appendable to write to.
+ * @throws IOException on error.
+ */
+ public void writeSummary(final Appendable appendable) throws IOException {
+ appendable.append("RAT summary:").append(System.lineSeparator());
+ for (ClaimStatistic.Counter counter : ClaimStatistic.Counter.values()) {
+ appendable.append(" ").append(counter.displayName()).append(": ")
+ .append(Integer.toString(statistic.getCounter(counter)))
+ .append(System.lineSeparator());
+ }
+ }
+
+ public static final class Builder {
+ /**
+ * The document that was generated.
+ */
+ private Document document;
+ /**
+ * The claim statistic from the execution that generated the document.
+ * May be empty if the Document was read from disk.
+ */
+ private ClaimStatistic statistic;
+ /**
+ * The configuration that generated the document
+ */
+ private ReportConfiguration configuration;
+
+ public Builder document(final Document document) {
+ this.document = document;
+ return this;
+ }
+
+ public Builder document(final String fileName, final DocumentName workingDirectory) {
+ File inputFile = workingDirectory.resolve(fileName).asFile();
+ try (InputStream inputStream = new FileInputStream(inputFile)) {
+ this.document = StandardXmlFactory.documentBuilder().parse(inputStream);
+ } catch (SAXException | IOException e) {
+ throw new ConfigurationException("Unable to read file: " + inputFile, e);
+ }
+ return this;
+ }
+
+ public Output build() {
+ return new Output(this);
+ }
+
+ public Builder statistic(final ClaimStatistic statistic) {
+ this.statistic = statistic;
+ return this;
+ }
+
+ public Builder statistic(final String fileName, final DocumentName workingDirectory) {
+ File sourceFile = workingDirectory.resolve(fileName).asFile();
+ try {
+ ClaimStatistic newStatistic = new ClaimStatistic();
+ newStatistic.serDes().deserialize(() -> new FileInputStream(sourceFile));
+ this.statistic = newStatistic;
+ return this;
+ } catch (IOException e) {
+ throw new ConfigurationException("Unable to read file: " + sourceFile, e);
+ }
+ }
+
+ public Builder configuration(final ReportConfiguration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ public Builder configuration(final String fileName, final DocumentName workingDirectory) {
+ File configurationFile = workingDirectory.resolve(fileName).asFile();
+ try {
+ ReportConfiguration config = new ReportConfiguration();
+ config.serDes().deserialize(() -> new FileInputStream(configurationFile), workingDirectory);
+ this.configuration = config;
+ return this;
+ } catch (IOException e) {
+ throw new ConfigurationException("Unable to read file: " + configurationFile, e);
+ }
+ }
+ }
}
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
index b56e0dde7..ea0c11133 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/StyleSheets.java
@@ -71,8 +71,8 @@ public enum StyleSheets {
}
/**
- * Gets the IOSupplier for a style sheet.
- * @return an IOSupplier for the sheet.
+ * Gets the IODescriptor for a style sheet.
+ * @return an IODescriptor for the sheet.
*/
public ReportConfiguration.IODescriptor getStyleSheet() {
URL url = StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", name));
@@ -81,9 +81,9 @@ public ReportConfiguration.IODescriptor getStyleSheet() {
}
/**
- * Gets the IOSupplier for a style sheet.
+ * Gets the IODescriptor for a style sheet.
* @param name the short name for or the path to a style sheet.
- * @return the IOSupplier for the style sheet.
+ * @return the IODescriptor for the style sheet.
*/
public static ReportConfiguration.IODescriptor getStyleSheet(final String name) {
URL url = StyleSheets.class.getClassLoader().getResource(format("org/apache/rat/%s.xsl", name));
diff --git a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionProcessor.java b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionProcessor.java
index d7b5862be..d57e21181 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionProcessor.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/config/exclusion/ExclusionProcessor.java
@@ -20,17 +20,25 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.rat.configuration.XMLConfigurationReader;
import org.apache.rat.document.DocumentName;
import org.apache.rat.document.DocumentNameMatcher;
+import org.apache.rat.report.xml.writer.XmlWriter;
import org.apache.rat.utils.DefaultLog;
import org.apache.rat.utils.ExtendedIterator;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import static java.lang.String.format;
@@ -74,21 +82,66 @@ public ExclusionProcessor() {
excludedCollections = new HashSet<>();
}
- /** Reset the {@link #lastMatcher} and {@link #lastMatcherBaseDir} to start again */
+ public SerDes serDes() {
+ return new SerDes();
+ }
+
+ /* the following set of methods are here for testing purposes */
+ Set getExcludedPatterns() {
+ return new HashSet<>(excludedPatterns);
+ }
+
+ Collection getExcludedPaths() {
+ return new ArrayList<>(excludedPaths);
+ }
+
+ Set getIncludedPatterns() {
+ return new HashSet<>(includedPatterns);
+ }
+
+ Collection getIncludedPaths() {
+ return new ArrayList<>(includedPaths);
+ }
+
+ Collection getFileProcessors() {
+ return new HashSet<>(fileProcessors);
+ }
+
+ Set getIncludedCollections() {
+ return new HashSet<>(includedCollections);
+ }
+
+ Set getExcludedCollections() {
+ return new HashSet<>(excludedCollections);
+ }
+
+ DocumentNameMatcher getLastMatcher() {
+ return lastMatcher;
+ }
+
+ DocumentName getLastMatcherBaseDir() {
+ return lastMatcherBaseDir;
+ }
+
+ /**
+ * Reset the {@link #lastMatcher} and {@link #lastMatcherBaseDir} to start again.
+ */
private void resetLastMatcher() {
lastMatcher = null;
lastMatcherBaseDir = null;
}
/**
- * Add the Iterable of strings to the collection of file/directory patters to ignore.
- * @param patterns the patterns to add
+ * Add the iterable of strings to the collection of file/directory patters to ignore.
+ * @param patterns the patterns to add.
* @return this
*/
public ExclusionProcessor addIncludedPatterns(final Iterable patterns) {
+ if (patterns != null) {
DefaultLog.getInstance().debug(format("Including patterns: %s", String.join(", ", patterns)));
patterns.forEach(includedPatterns::add);
resetLastMatcher();
+ }
return this;
}
@@ -139,9 +192,11 @@ public ExclusionProcessor addIncludedCollection(final StandardCollection collect
* @return this
*/
public ExclusionProcessor addExcludedPatterns(final Iterable patterns) {
+ if (patterns != null) {
DefaultLog.getInstance().debug(format("Excluding patterns: %s", String.join(", ", patterns)));
patterns.forEach(excludedPatterns::add);
resetLastMatcher();
+ }
return this;
}
@@ -177,9 +232,11 @@ public void reportExclusions(final Appendable appendable) throws IOException {
for (DocumentNameMatcher nameMatcher : excludedPaths) {
appendable.append(format("Excluding %s.%n", nameMatcher.toString()));
}
+ for (DocumentNameMatcher nameMatcher : includedPaths) {
+ appendable.append(format("Including %s.%n", nameMatcher.toString()));
+ }
}
-
/**
* Excludes the files/directories specified by a StandardCollection.
* @param collection the StandardCollection that identifies the files to exclude.
@@ -203,7 +260,7 @@ public ExclusionProcessor addExcludedCollection(final StandardCollection collect
public DocumentNameMatcher getNameMatcher(final DocumentName basedir) {
// if lastMatcher is not set or the basedir is not the same as the last one then
// we have to regenerate the matching document.
- // Otherwise we can just return the lastMatcher since there is no change.
+ // Otherwise, we can just return the lastMatcher since there is no change.
if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) {
lastMatcherBaseDir = basedir;
@@ -337,4 +394,90 @@ private void extractPaths(final MatcherSet.Builder matcherBuilder) {
}
}
+ /**
+ * Serializes and deserializes the ExclusionProcessor to an XML document.
+ */
+ public class SerDes {
+ /** The pattern attribute name */
+ private static final String PATTERN = "pattern";
+ /** THe name attribute name */
+ private static final String NAME = "name";
+
+ /**
+ * Serialize the ExclusionProcessor to XML writer.
+ * @param writer the writer to serialize to.
+ * @throws IOException on Error
+ */
+ public void serialize(final XmlWriter writer) throws IOException {
+ writer.startElement("ExclusionProcessor");
+
+ for (String pattern : excludedPatterns) {
+ writer.startElement("excludedPattern").attribute(PATTERN, pattern).closeElement();
+ }
+ for (StandardCollection obj : excludedCollections) {
+ writer.startElement("excludedCollection").attribute(NAME, obj.name()).closeElement();
+ }
+ for (DocumentNameMatcher obj : excludedPaths) {
+ writer.startElement("excludedPath").attribute(NAME, obj.toString()).closeElement();
+ }
+
+ for (String pattern : includedPatterns) {
+ writer.startElement("includedPattern").attribute(PATTERN, pattern).closeElement();
+ }
+ for (StandardCollection obj : includedCollections) {
+ writer.startElement("includedCollection").attribute(NAME, obj.name()).closeElement();
+ }
+ for (DocumentNameMatcher obj : includedPaths) {
+ writer.startElement("includedPath").attribute(NAME, obj.toString()).closeElement();
+ }
+
+ for (StandardCollection obj : fileProcessors) {
+ writer.startElement("fileProcessor").attribute(NAME, obj.name()).closeElement();
+ }
+ writer.closeElement();
+ }
+
+ /**
+ * Deserialize from XML Document node to ExclusionProcessor.
+ * @param xmlNode the node to deserialize from.
+ */
+ public void deserialize(final Node xmlNode) {
+ final NodeList children = xmlNode.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ Map attributes = XMLConfigurationReader.attributes(child);
+ switch (child.getNodeName()) {
+ case "excludedPattern" ->
+ excludedPatterns.add(attributes.get(PATTERN));
+
+ case "excludedCollection" ->
+ excludedCollections.add(StandardCollection.valueOf(attributes.get(NAME)));
+
+ case "excludedPath" ->
+ excludedPaths.add(new DocumentNameMatcher(attributes.get(NAME),
+ (Predicate) x -> {
+ throw new NotImplementedException("Deserialized ExclusionProcessor can not evaluate excluded paths");
+ }));
+
+ case "includedPattern" ->
+ includedPatterns.add(attributes.get(PATTERN));
+
+ case "includedCollection" ->
+ includedCollections.add(StandardCollection.valueOf(attributes.get(NAME)));
+
+ case "includedPath" ->
+ includedPaths.add(new DocumentNameMatcher(attributes.get(NAME),
+ (Predicate) x -> {
+ throw new NotImplementedException("Deserialized ExclusionProcessor can not evaluate included paths");
+ }));
+
+ case "fileProcessor" ->
+ fileProcessors.add(StandardCollection.valueOf(attributes.get(NAME)));
+
+ default ->
+ DefaultLog.getInstance().error(String.format("Unknown child node '%s'", child.getNodeName()));
+ }
+ }
+ }
+ }
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java
index ac11bdd5a..ba20fd5fd 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/configuration/XMLConfigurationReader.java
@@ -123,7 +123,7 @@ public SortedSet licenseFamilies() {
/**
* Creates textual representation of a node for display.
* @param node the node to create the textual representation of.
- * @return The textual representation of the node for display.
+ * @return the textual representation of the node for display.
*/
private String nodeText(final Node node) {
StringBuilder stringBuilder = new StringBuilder().append("<").append(node.getNodeName());
@@ -154,7 +154,7 @@ public void read(final Reader reader) {
/**
* Read the uris and extract the DOM information to create new objects.
- * @param uris The URIs to read.
+ * @param uris the URIs to read.
*/
public void read(final URI... uris) {
DocumentBuilder builder = StandardXmlFactory.documentBuilder();
@@ -170,10 +170,10 @@ public void read(final URI... uris) {
/**
* Applies the {@code consumer} to each node in the {@code list}. Generally used for extracting info from a
* {@code NodeList}.
- * @param list the NodeList to process
+ * @param list the NodeList to process.
* @param consumer the consumer to apply to each node in the list.
*/
- private void nodeListConsumer(final NodeList list, final Consumer consumer) {
+ public static void nodeListConsumer(final NodeList list, final Consumer consumer) {
for (int i = 0; i < list.getLength(); i++) {
consumer.accept(list.item(i));
}
@@ -196,10 +196,10 @@ public void add(final Document newDoc) {
/**
* Get a map of Node attribute names to values.
- * @param node The node to process
+ * @param node the node to process.
* @return the map of attributes on the node.
*/
- private Map attributes(final Node node) {
+ public static Map attributes(final Node node) {
NamedNodeMap nnm = node.getAttributes();
Map result = new HashMap<>();
for (int i = 0; i < nnm.getLength(); i++) {
@@ -211,9 +211,9 @@ private Map attributes(final Node node) {
/**
* Finds the setter description property in the builder and set it with the value.
- * @param desc The description for the setter.
- * @param builder The builder to set the value in.
- * @param value The value to set.
+ * @param desc the description for the setter.
+ * @param builder the builder to set the value in.
+ * @param value the value to set.
*/
private void callSetter(final Description desc, final IHeaderMatcher.Builder builder, final Object value) {
try {
@@ -226,7 +226,7 @@ private void callSetter(final Description desc, final IHeaderMatcher.Builder bui
/**
* For any children of description that are BUILD_PARAMETERS set the builder property.
- * @param description The description for the builder.
+ * @param description the description for the builder.
* @param builder the builder to set the properties in.
*/
private void processBuilderParams(final Description description, final IHeaderMatcher.Builder builder) {
@@ -245,7 +245,7 @@ private void processBuilderParams(final Description description, final IHeaderMa
* of the child (if any) to the BiPredicate. If there is not a child description
* for the node it is ignored. If the node is processed it is removed from list
* of children.
- * @param description the Description of the node being processed
+ * @param description the description of the node being processed.
* @param children the child nodes of that node.
* @param childProcessor the function that handles the processing of the child
* node.
@@ -266,7 +266,7 @@ private void processChildren(final Description description, final List chi
/**
* Creates a child node processor for the builder described by the description.
- * @param builder The builder to set properties in.
+ * @param builder the builder to set properties in.
* @param description the description of the builder.
* @return child node.
*/
@@ -315,11 +315,11 @@ private void setValue(final Description description, final Description childDesc
* Process the ELEMENT_NODEs children of the parent whose names match child
* descriptions. All children of children are processed with the childProcessor. If
* the childProcessor handles the node it is not included in the resulting list.
- * @param description the Description of the parent node.
- * @param parent the node being processed
+ * @param description the description of the parent node.
+ * @param parent the node being processed.
* @param childProcessor the BiProcessor to handle process each child. If the
* processor handles the child it must return {@code true}.
- * @return A Pair comprising a boolean flag indicating children were found, and
+ * @return a Pair comprising a boolean flag indicating children were found, and
* a list of all child nodes that were not processed by the childProcessor.
*/
private Pair> processChildNodes(final Description description, final Node parent,
@@ -350,7 +350,7 @@ private Pair> processChildNodes(final Description descriptio
/**
* Creates a Builder from a Matcher node.
* @param matcherNode the Matcher node to parse.
- * @return The Builder for the matcher described by the node.
+ * @return the Builder for the matcher described by the node.
*/
private AbstractBuilder parseMatcher(final Node matcherNode) {
final AbstractBuilder builder = MatcherBuilderTracker.getMatcherBuilder(matcherNode.getNodeName());
@@ -391,7 +391,6 @@ private AbstractBuilder parseMatcher(final Node matcherNode) {
iter.remove();
}
}
-
} else {
processChildren(description, children, (child, childD) -> {
if (childD.getChildType().equals(description.getChildType())) {
@@ -401,7 +400,6 @@ private AbstractBuilder parseMatcher(final Node matcherNode) {
return false;
});
}
-
}
if (!children.isEmpty()) {
@@ -421,7 +419,7 @@ private BiPredicate licenseChildNodeProcessor(final ILicense.
switch (childDescription.getType()) {
case LICENSE:
throw new ConfigurationException(String.format(
- "%s may not be enclosed in another license. %s '%s' found in '%s'", childDescription.getType(),
+ "%s may not be enclosed in another license. %s '%s' found in '%s'", childDescription.getType(),
childDescription.getType(), childDescription.getCommonName(), description.getCommonName()));
case BUILD_PARAMETER:
break;
diff --git a/apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java b/apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java
index 62572916c..7279e3e81 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/report/claim/ClaimStatistic.java
@@ -19,14 +19,24 @@
package org.apache.rat.report.claim;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import javax.xml.parsers.DocumentBuilder;
+
+import org.apache.commons.io.function.IOSupplier;
import org.apache.commons.lang3.StringUtils;
import org.apache.rat.api.Document;
+import org.apache.rat.configuration.XMLConfigurationReader;
+import org.apache.rat.report.xml.writer.XmlWriter;
+import org.apache.rat.utils.StandardXmlFactory;
+import org.xml.sax.SAXException;
/**
* This class provides a numerical overview about
@@ -100,7 +110,7 @@ public int getDefaultMinValue() {
* @return displayName of the counter, capitalized and without underscores.
*/
public String displayName() {
- return StringUtils.capitalize(name().replaceAll("_", " ").toLowerCase(Locale.ROOT));
+ return StringUtils.capitalize(name().replace("_", " ").toLowerCase(Locale.ROOT));
}
}
@@ -113,8 +123,11 @@ public String displayName() {
/** Map of counter type to value */
private final ConcurrentHashMap counterMap = new ConcurrentHashMap<>();
+ public SerDes serDes() {
+ return new SerDes();
+ }
/**
- * Converts null counter to 0.
+ * Converts {@code null} counter to 0.
*
* @param counter the Counter to retrieve the value from.
* @return 0 if counter is {@code null} or counter value otherwise.
@@ -141,6 +154,15 @@ public void incCounter(final Counter counter, final int value) {
counterMap.compute(counter, (k, v) -> v == null ? new IntCounter().increment(value) : v.increment(value));
}
+ /**
+ * Increments the counts for the counter.
+ * @param counter the counter to increment.
+ * @param value the value to increment the counter by.
+ */
+ public void setCounter(final Counter counter, final int value) {
+ counterMap.put(counter, new IntCounter().increment(value));
+ }
+
/**
* Gets the counts for the Document.Type.
* @param documentType the Document.Type to get the counter for.
@@ -168,24 +190,12 @@ public List getDocumentTypes() {
public void incCounter(final Document.Type documentType, final int value) {
documentTypeMap.compute(documentType, (k, v) -> updateCounter(Counter.DOCUMENT_TYPES, v, value));
switch (documentType) {
- case STANDARD:
- incCounter(Counter.STANDARDS, value);
- break;
- case ARCHIVE:
- incCounter(Counter.ARCHIVES, value);
- break;
- case BINARY:
- incCounter(Counter.BINARIES, value);
- break;
- case NOTICE:
- incCounter(Counter.NOTICES, value);
- break;
- case UNKNOWN:
- incCounter(Counter.UNKNOWN, value);
- break;
- case IGNORED:
- incCounter(Counter.IGNORED, value);
- break;
+ case STANDARD -> incCounter(Counter.STANDARDS, value);
+ case ARCHIVE -> incCounter(Counter.ARCHIVES, value);
+ case BINARY -> incCounter(Counter.BINARIES, value);
+ case NOTICE -> incCounter(Counter.NOTICES, value);
+ case UNKNOWN -> incCounter(Counter.UNKNOWN, value);
+ case IGNORED -> incCounter(Counter.IGNORED, value);
}
}
@@ -208,10 +218,10 @@ public int getLicenseNameCount(final String licenseName) {
}
/**
- * Updates the intCounter with the value and if the intCounter was null creates a new one and registers the
+ * Updates the intCounter with the value and if the intCounter was {@code null} creates a new one and registers the
* creation as a counter type.
* @param counter the Type of the counter.
- * @param intCounter the IntCounter to update. May be null.
+ * @param intCounter the IntCounter to update. May be {@code null}.
* @param value the value to add to the int counter.
* @return the intCounter if it was not {@code null}, a new IntCounter otherwise.
*/
@@ -288,5 +298,105 @@ public IntCounter increment(final int count) {
public int value() {
return value;
}
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ /**
+ * Serialize and deserialize the claim Statistic.
+ */
+ public class SerDes {
+ /** The count attribute string. */
+ private static final String COUNT = "count";
+ /** The name attribute string. */
+ private static final String NAME = "name";
+
+ /**
+ * Serializes the claim statistic into an appendable.
+ * @param appendable the appendable to write to.
+ * @throws IOException on error.
+ */
+ public void serialize(final Appendable appendable) throws IOException {
+ try (XmlWriter writer = new XmlWriter(appendable)) {
+ writer.startDocument().startElement("ClaimStatistic")
+ .startElement("licenseNameMap");
+ for (Map.Entry entry : licenseNameMap.entrySet()) {
+ if (entry.getValue().value > 0) {
+ writer.startElement("licenseName")
+ .attribute(COUNT, entry.getValue().toString())
+ .attribute(NAME, entry.getKey()).closeElement();
+ }
+ }
+ writer.closeElement()
+ .startElement("licenseFamilyCategoryMap");
+ for (Map.Entry entry : licenseFamilyCategoryMap.entrySet()) {
+ if (entry.getValue().value > 0) {
+ writer.startElement("familyCategory")
+ .attribute(COUNT, entry.getValue().toString())
+ .attribute(NAME, entry.getKey()).closeElement();
+ }
+ }
+ writer.closeElement()
+ .startElement("documentTypeMap");
+ for (Map.Entry entry : documentTypeMap.entrySet()) {
+ if (entry.getValue().value > 0) {
+ writer.startElement("documentType")
+ .attribute(COUNT, entry.getValue().toString())
+ .attribute(NAME, entry.getKey().name()).closeElement();
+ }
+ }
+ writer.closeElement()
+ .startElement("counterMap");
+ for (Map.Entry entry : counterMap.entrySet()) {
+ if (entry.getValue().value > 0) {
+ writer.startElement("counter")
+ .attribute(COUNT, entry.getValue().toString())
+ .attribute(NAME, entry.getKey().name()).closeElement();
+ }
+ }
+ writer.closeElement();
+ }
+ }
+
+ /**
+ * Deserializes a ClaimStatistic from an input stream.
+ * @param inputStreamSupplier the supplier of the input stream to deserialize from.
+ * @throws IOException on error.
+ */
+ public void deserialize(final IOSupplier inputStreamSupplier) throws IOException {
+ DocumentBuilder builder = StandardXmlFactory.documentBuilder();
+ org.w3c.dom.Document document;
+
+ try (InputStream stream = inputStreamSupplier.get()) {
+ document = builder.parse(stream);
+ } catch (SAXException e) {
+ throw new IOException("Unable to read input", e);
+ }
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("licenseName"), node -> {
+ Map attributes = XMLConfigurationReader.attributes(node);
+ incLicenseNameCount(attributes.get(NAME), Integer.parseInt(attributes.get(COUNT)));
+ });
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("familyCategory"), node -> {
+ Map attributes = XMLConfigurationReader.attributes(node);
+ incLicenseCategoryCount(attributes.get(NAME), Integer.parseInt(attributes.get(COUNT)));
+ });
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("documentType"), node -> {
+ Map attributes = XMLConfigurationReader.attributes(node);
+ Document.Type type = Document.Type.valueOf(attributes.get(NAME));
+ incCounter(type, Integer.parseInt(attributes.get(COUNT)));
+ });
+
+ XMLConfigurationReader.nodeListConsumer(document.getElementsByTagName("counter"), node -> {
+ Map attributes = XMLConfigurationReader.attributes(node);
+ Counter type = Counter.valueOf(attributes.get(NAME));
+ setCounter(type, Integer.parseInt(attributes.get(COUNT)));
+ });
+ }
}
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/utils/StandardXmlFactory.java b/apache-rat-core/src/main/java/org/apache/rat/utils/StandardXmlFactory.java
index 3ec9849a7..b6a0339e8 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/utils/StandardXmlFactory.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/utils/StandardXmlFactory.java
@@ -18,7 +18,12 @@
*/
package org.apache.rat.utils;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
@@ -27,9 +32,17 @@
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
+import org.apache.commons.lang3.StringUtils;
+import org.w3c.dom.Document;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
/**
* Factory to create standard XML objects. The intention of this class is to resolve in a consistent manner the
* XXE errors and similar XML IO errors.
@@ -62,6 +75,7 @@ public static Transformer createTransformer() throws TransformerConfigurationExc
* @return the transformer.
* @throws TransformerConfigurationException on error.
*/
+ @SuppressFBWarnings("MALICIOUS_XSLT")
public static Transformer createTransformer(final InputStream styleIn) throws TransformerConfigurationException {
TransformerFactory factory = TransformerFactory.newInstance(); // NOSONAR
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
@@ -94,4 +108,29 @@ public static DocumentBuilder documentBuilder() {
throw new IllegalStateException("No XML parser defined", e);
}
}
+
+ /**
+ * Write an XML document to a file.
+ * @param document the document to write.
+ * @param file the file to write to.
+ */
+ public static void writeDocument(final Document document, final File file) throws IOException, TransformerException {
+ DOMSource source = new DOMSource(document);
+ FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8);
+ StreamResult result = new StreamResult(writer);
+ createTransformer().transform(source, result);
+ }
+
+ /**
+ * Write an XML document to a file.
+ * @param document the document to write.
+ */
+ public static String serializeDocument(final Document document) throws TransformerException {
+ DOMSource source = new DOMSource(document);
+ StringWriter writer = new StringWriter();
+ StreamResult sink = new StreamResult(writer);
+ createTransformer().transform(source, sink);
+ String result = writer.toString();
+ return StringUtils.defaultIfBlank(result, "");
+ }
}
diff --git a/apache-rat-core/src/test/java/org/apache/rat/OutputTest.java b/apache-rat-core/src/test/java/org/apache/rat/OutputTest.java
new file mode 100644
index 000000000..f523f55e3
--- /dev/null
+++ b/apache-rat-core/src/test/java/org/apache/rat/OutputTest.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * https://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ */
+package org.apache.rat;
+
+import org.apache.commons.io.function.IOSupplier;
+import org.apache.rat.api.RatException;
+import org.apache.rat.commandline.StyleSheets;
+import org.apache.rat.config.AddLicenseHeaders;
+import org.apache.rat.config.exclusion.StandardCollection;
+import org.apache.rat.config.results.ClaimValidator;
+import org.apache.rat.document.DocumentName;
+import org.apache.rat.document.DocumentNameMatcher;
+import org.apache.rat.document.FileDocument;
+import org.apache.rat.license.LicenseSetFactory;
+import org.apache.rat.report.claim.ClaimStatistic;
+import org.apache.rat.report.claim.ClaimStatisticTest;
+import org.apache.rat.test.utils.Resources;
+import org.apache.rat.testhelpers.FileUtils;
+import org.apache.rat.utils.StandardXmlFactory;
+import org.apache.rat.utils.StandardXmlFactoryTest;
+import org.apache.rat.walker.DirectoryWalker;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+import org.xmlunit.assertj3.XmlAssert;
+
+import javax.xml.transform.TransformerException;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class OutputTest {
+
+ static Path tempPath;
+
+ @BeforeAll
+ static void setup() throws IOException {
+ tempPath = Files.createTempDirectory("outputTest").toAbsolutePath();
+ }
+
+ @AfterAll
+ static void teardown() {
+ FileUtils.delete(tempPath.toFile());
+ }
+
+ @Test
+ void documentReadingTest() throws IOException, SAXException, TransformerException {
+ Path testPath = tempPath.resolve("documentReading");
+ File testFile = testPath.toFile();
+ FileUtils.mkDir(testFile);
+ DocumentName workingDirectory = DocumentName.builder(testPath.toFile()).setBaseName(testFile).build();
+ Document document;
+ DocumentName documentFile = workingDirectory.resolve("document.xml");
+ try (InputStream inputStream = OutputTest.class.getClassLoader().getResourceAsStream("XmlOutputExamples/elements.xml")) {
+ document = StandardXmlFactory.documentBuilder().parse(inputStream);
+ StandardXmlFactory.writeDocument(document, documentFile.asFile());
+ }
+
+ Reporter.Output.Builder builder = Reporter.Output.builder().document(documentFile.getName(), workingDirectory);
+
+ Reporter.Output output = builder.build();
+ XmlAssert.assertThat(output.getDocument()).and(document)
+ .ignoreWhitespace()
+ .areIdentical();
+ }
+
+ @Test
+ void statisticReadingTest() throws IOException {
+ Path testPath = tempPath.resolve("statisticReading");
+ File testFile = testPath.toFile();
+ FileUtils.mkDir(testFile);
+ DocumentName workingDirectory = DocumentName.builder(testPath.toFile()).setBaseName(testFile).build();
+ DocumentName documentFile = workingDirectory.resolve("statistic.xml");
+
+ ClaimStatistic underTest = new ClaimStatistic();
+ underTest.incLicenseCategoryCount("familyCategory", 1);
+ underTest.incCounter(ClaimStatistic.Counter.APPROVED, 2);
+ underTest.incCounter(org.apache.rat.api.Document.Type.IGNORED, 3);
+ underTest.incLicenseNameCount("licenseName", 4);
+
+ ClaimStatistic.SerDes serDes = underTest.serDes();
+ StringWriter stringWriter = new StringWriter();
+ serDes.serialize(stringWriter);
+ try (FileOutputStream fos = new FileOutputStream(documentFile.asFile())) {
+ fos.write(stringWriter.toString().getBytes(StandardCharsets.UTF_8));
+ }
+
+ Reporter.Output.Builder builder = Reporter.Output.builder().statistic(documentFile.getName(), workingDirectory);
+
+ Reporter.Output output = builder.build();
+ ClaimStatisticTest.assertSame(output.getStatistic(), underTest);
+ }
+
+ @Test
+ void readingBadFileTest() {
+ Path testPath = tempPath.resolve("readingBadFileTest");
+ File testFile = testPath.toFile();
+ FileUtils.mkDir(testFile);
+ DocumentName workingDirectory = DocumentName.builder(testPath.toFile()).setBaseName(testFile).build();
+ DocumentName documentFile = workingDirectory.resolve("missing.file");
+ String name = documentFile.getName();
+ Reporter.Output.Builder builder = Reporter.Output.builder();
+ assertThatThrownBy(() -> builder.statistic(name, workingDirectory))
+ .as("statistic read")
+ .isInstanceOf(ConfigurationException.class)
+ .hasMessageContaining("Unable to read file: " + testPath.resolve("missing.file"));
+
+ assertThatThrownBy(() -> builder.configuration(name, workingDirectory))
+ .as("configuration read")
+ .isInstanceOf(ConfigurationException.class)
+ .hasMessageContaining("Unable to read file: " + testPath.resolve("missing.file"));
+
+ assertThatThrownBy(() -> builder.document(name, workingDirectory))
+ .as("document read")
+ .isInstanceOf(ConfigurationException.class)
+ .hasMessageContaining("Unable to read file: " + testPath.resolve("missing.file"));
+ }
+
+ @Test
+ void configurationReadingTest() throws IOException {
+ Path testPath = tempPath.resolve("configurationReading");
+ File testFile = testPath.toFile();
+ FileUtils.mkDir(testFile);
+ DocumentName workingDirectory = DocumentName.builder(testPath.toFile()).setBaseName(testFile).build();
+ DocumentName documentFile = workingDirectory.resolve("configuration.xml");
+
+ ReportConfiguration underTest = new ReportConfiguration();
+ underTest.setAddLicenseHeaders(AddLicenseHeaders.FORCED);
+ underTest.listFamilies(LicenseSetFactory.LicenseFilter.APPROVED);
+ underTest.listLicenses(LicenseSetFactory.LicenseFilter.ALL);
+ underTest.setDryRun(true);
+ underTest.setArchiveProcessing(ReportConfiguration.Processing.NOTIFICATION);
+ underTest.setStandardProcessing(ReportConfiguration.Processing.ABSENCE);
+ underTest.setStyleSheet(StyleSheets.MISSING_HEADERS.getStyleSheet());
+ underTest.setOut(new File("/some/file/somewhere"));
+ underTest.setCopyrightMessage("the copyright message");
+ underTest.addSource(new File("/my/file"));
+ underTest.addSource(new ReportConfigurationTest.TestingReportable());
+ underTest.addExcludedPatterns(List.of("pattern/**", "pattern2/**"));
+ underTest.addExcludedCollection(StandardCollection.BAZAAR);
+ underTest.addExcludedCollection(StandardCollection.MISC);
+ underTest.addExcludedFileProcessor(StandardCollection.HIDDEN_FILE);
+ underTest.addExcludedMatcher(DocumentNameMatcher.MATCHES_ALL);
+ underTest.addIncludedPatterns(List.of("**/pattern3", "**/pattern4"));
+ underTest.addIncludedCollection(StandardCollection.ARCH);
+ underTest.addIncludedCollection(StandardCollection.BITKEEPER);
+ underTest.addIncludedMatcher(DocumentNameMatcher.MATCHES_NONE);
+
+ ClaimValidator claimValidator = underTest.getClaimValidator();
+ claimValidator.setMax(ClaimStatistic.Counter.APPROVED, 5);
+ claimValidator.setMin(ClaimStatistic.Counter.APPROVED, 3);
+ claimValidator.setMax(ClaimStatistic.Counter.ARCHIVES, 10);
+ claimValidator.setMin(ClaimStatistic.Counter.BINARIES, 4);
+
+ StringWriter stringWriter = new StringWriter();
+ underTest.serDes().serialize(stringWriter);
+
+ try (FileOutputStream fos = new FileOutputStream(documentFile.asFile())) {
+ fos.write(stringWriter.toString().getBytes(StandardCharsets.UTF_8));
+ }
+
+ Reporter.Output.Builder builder = Reporter.Output.builder().configuration(documentFile.getName(), workingDirectory);
+
+ Reporter.Output output = builder.build();
+ ReportConfigurationTest.assertSame(output.getConfiguration(), underTest);
+ }
+
+ private ReportConfiguration initializeConfiguration() throws URISyntaxException {
+ Defaults defaults = Defaults.builder().build();
+ final File elementsFile = Resources.getExampleResource("exampleData");
+ final ReportConfiguration configuration = new ReportConfiguration();
+ configuration.setFrom(defaults);
+ DocumentName documentName = DocumentName.builder(elementsFile).build();
+ configuration.addSource(new DirectoryWalker(new FileDocument(documentName, elementsFile,
+ configuration.getDocumentExcluder(documentName))));
+ return configuration;
+ }
+
+ @Test
+ void listLicensesReportTest() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ReportConfiguration configuration = initializeConfiguration();
+ configuration.setOut(new ReportConfiguration.IODescriptor<>("listLicensesReportTest", () -> out));
+ configuration.setStyleSheet(StyleSheets.UNAPPROVED_LICENSES.getStyleSheet());
+ Reporter.Output output = Reporter.Output.builder()
+ .statistic(new ClaimStatistic())
+ .document(null)
+ .configuration(configuration)
+ .build();
+ output.listLicenses(LicenseSetFactory.LicenseFilter.NONE);
+
+ out.flush();
+ String document = out.toString();
+ assertThat(document).contains("Licenses (NONE):");
+ StringWriter writer = new StringWriter();
+ try (PrintWriter printWriter = new PrintWriter(writer)) {
+ output.listLicenses(printWriter, LicenseSetFactory.LicenseFilter.ALL);
+ }
+ assertThat(writer.toString()).contains("Licenses (ALL):");
+ }
+
+ @Test
+ void formatTest() throws IOException, SAXException {
+ Reporter.Output output = Reporter.Output.builder()
+ .statistic(new ClaimStatistic())
+ .document(StandardXmlFactoryTest.simpleDocument())
+ .configuration(new ReportConfiguration())
+ .build();
+
+ IOSupplier badStyleSheet = () -> new InputStream() {
+ @Override
+ public int read() throws IOException {
+ throw new IOException("Expected exception.");
+ }
+ };
+ assertThatThrownBy(() -> output.format(badStyleSheet, ReportConfiguration.SYSTEM_OUT.ioSupplier()))
+ .as("badStyleSheet")
+ .isInstanceOf(RatException.class)
+ .hasMessageContaining("Expected exception")
+ .hasCauseInstanceOf(TransformerException.class);
+
+ IOSupplier missingStyleSheet = () -> {throw new IOException("Expected exception.");};
+
+
+ assertThatThrownBy(() -> output.format(missingStyleSheet, ReportConfiguration.SYSTEM_OUT.ioSupplier()))
+ .as("missingStyleSheet")
+ .isInstanceOf(RatException.class)
+ .hasMessageContaining("Expected exception")
+ .hasCauseInstanceOf(IOException.class);
+
+ IOSupplier badOutput = () -> new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ throw new IOException("Expected exception.");
+ }
+ };
+ assertThatThrownBy(() -> output.format(StyleSheets.XML.getStyleSheet().ioSupplier(), badOutput))
+ .as("badOutput")
+ .isInstanceOf(RatException.class)
+ .hasMessageContaining("Expected exception")
+ .hasCauseInstanceOf(TransformerException.class);
+
+ IOSupplier missingOutput = () -> {throw new IOException("Expected exception.");};
+ assertThatThrownBy(() -> output.format(StyleSheets.XML.getStyleSheet().ioSupplier(), missingOutput))
+ .as("missingOutput")
+ .isInstanceOf(RatException.class)
+ .hasMessageContaining("Expected exception")
+ .hasCauseInstanceOf(IOException.class);
+
+ }
+}
diff --git a/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java b/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
index 7d6040433..098669e82 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/ReportConfigurationTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
@@ -32,9 +33,11 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -44,15 +47,21 @@
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.output.CloseShieldOutputStream;
import org.apache.rat.analysis.IHeaderMatcher;
+import org.apache.rat.api.RatException;
+import org.apache.rat.commandline.StyleSheets;
import org.apache.rat.config.AddLicenseHeaders;
+import org.apache.rat.config.exclusion.ExclusionProcessorTest;
import org.apache.rat.config.exclusion.StandardCollection;
+import org.apache.rat.config.results.ClaimValidator;
import org.apache.rat.configuration.XMLConfigurationReaderTest;
import org.apache.rat.document.DocumentName;
import org.apache.rat.document.DocumentNameMatcher;
import org.apache.rat.license.ILicense;
import org.apache.rat.license.ILicenseFamily;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
+import org.apache.rat.report.RatReport;
import org.apache.rat.report.Reportable;
+import org.apache.rat.report.claim.ClaimStatistic;
import org.apache.rat.testhelpers.TestingLog;
import org.apache.rat.testhelpers.TestingLicense;
import org.apache.rat.testhelpers.TestingMatcher;
@@ -463,7 +472,7 @@ void outputTest() throws IOException {
assertThat(underTest.getWriter()).isNotNull();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
- underTest.setOut(new ReportConfiguration.IODescriptor("outputTest", () -> stream));
+ underTest.setOut(new ReportConfiguration.IODescriptor<>("outputTest", () -> stream));
assertThat(underTest.getOutput().get()).isEqualTo(stream);
PrintWriter writer = underTest.getWriter().get();
assertThat(writer).isNotNull();
@@ -490,7 +499,7 @@ void stylesheetTest() throws IOException, URISyntaxException {
assertThat(underTest.getStyleSheetDescriptor()).isNull();
assertThat(underTest.getStyleSheet()).isNull();
InputStream stream = mock(InputStream.class);
- underTest.setStyleSheet(new ReportConfiguration.IODescriptor("stylesheetTest", () -> stream));
+ underTest.setStyleSheet(new ReportConfiguration.IODescriptor<>("stylesheetTest", () -> stream));
assertThat(underTest.getStyleSheetDescriptor().ioSupplier().get()).isEqualTo(stream);
assertThat(underTest.getStyleSheet().get()).isEqualTo(stream);
@@ -551,7 +560,7 @@ void testValidate() {
void testSetOut() throws IOException {
ReportConfiguration config = new ReportConfiguration();
try (OutputStreamInterceptor osi = new OutputStreamInterceptor()) {
- config.setOut(new ReportConfiguration.IODescriptor("testSetOut",() -> osi));
+ config.setOut(new ReportConfiguration.IODescriptor<>("testSetOut",() -> osi));
assertThat(osi.closeCount).isEqualTo(0);
try (OutputStream os = config.getOutput().get()) {
assertThat(os).isNotNull();
@@ -760,6 +769,64 @@ public static void validateDefault(ReportConfiguration config) {
validateDefaultLicenses(config);
}
+ public static void assertSame(ReportConfiguration actual, ReportConfiguration expected) {
+ assertThat(actual.isAddingLicenses()).isEqualTo(expected.isAddingLicenses());
+ assertThat(actual.isAddingLicensesForced()).isEqualTo(expected.isAddingLicensesForced());
+ assertThat(actual.listFamilies()).isEqualTo(expected.listFamilies());
+ assertThat(actual.listLicenses()).isEqualTo(expected.listLicenses());
+ assertThat(actual.isDryRun()).isEqualTo(expected.isDryRun());
+ assertThat(actual.getArchiveProcessing()).isEqualTo(expected.getArchiveProcessing());
+ assertThat(actual.getStandardProcessing()).isEqualTo(expected.getStandardProcessing());
+ assertThat(actual.getStyleSheetDescriptor().name()).isEqualTo(expected.getStyleSheetDescriptor().name());
+ assertThat(actual.getOutputDescriptor().name()).isEqualTo(expected.getOutputDescriptor().name());
+
+ assertThat(actual.getCopyrightMessage()).isEqualTo(expected.getCopyrightMessage());
+
+ assertThat(actual.sources()).containsExactlyElementsOf(expected.sources());
+ assertThat(actual.reportables()).containsExactlyElementsOf(expected.reportables().toList());
+ ExclusionProcessorTest.assertSame(actual.getExclusionProcessor(), expected.getExclusionProcessor());
+
+ }
+ @Test
+ void serDesTest() throws IOException {
+ underTest.setAddLicenseHeaders(AddLicenseHeaders.FORCED);
+ underTest.listFamilies(LicenseFilter.APPROVED);
+ underTest.listLicenses(LicenseFilter.ALL);
+ underTest.setDryRun(true);
+ underTest.setArchiveProcessing(ReportConfiguration.Processing.NOTIFICATION);
+ underTest.setStandardProcessing(ReportConfiguration.Processing.ABSENCE);
+ underTest.setStyleSheet(StyleSheets.MISSING_HEADERS.getStyleSheet());
+ underTest.setOut(new File("/some/file/somewhere"));
+ underTest.setCopyrightMessage("the copyright message");
+ underTest.addSource(new File("/my/file"));
+ underTest.addSource(new TestingReportable());
+
+ underTest.addExcludedPatterns(List.of("pattern/**", "pattern2/**"));
+ underTest.addExcludedCollection(StandardCollection.BAZAAR);
+ underTest.addExcludedCollection(StandardCollection.MISC);
+ underTest.addExcludedFileProcessor(StandardCollection.HIDDEN_FILE);
+ underTest.addExcludedMatcher(DocumentNameMatcher.MATCHES_ALL);
+ underTest.addIncludedPatterns(List.of("**/pattern3", "**/pattern4"));
+ underTest.addIncludedCollection(StandardCollection.ARCH);
+ underTest.addIncludedCollection(StandardCollection.BITKEEPER);
+ underTest.addIncludedMatcher(DocumentNameMatcher.MATCHES_NONE);
+
+ ClaimValidator claimValidator = underTest.getClaimValidator();
+
+ claimValidator.setMax(ClaimStatistic.Counter.APPROVED, 5);
+ claimValidator.setMin(ClaimStatistic.Counter.APPROVED, 3);
+ claimValidator.setMax(ClaimStatistic.Counter.ARCHIVES, 10);
+ claimValidator.setMin(ClaimStatistic.Counter.BINARIES, 4);
+
+ StringWriter stringWriter = new StringWriter();
+ underTest.serDes().serialize(stringWriter);
+
+ ReportConfiguration actual = new ReportConfiguration();
+ actual.serDes().deserialize(() -> new ByteArrayInputStream(stringWriter.toString().getBytes(StandardCharsets.UTF_8)),
+ DocumentName.builder(new File("/rootDir")).build());
+ assertSame(actual, underTest);
+ }
+
/**
* A class to act as an output stream and count the number of close operations.
*/
@@ -776,4 +843,20 @@ public void close() {
++closeCount;
}
}
+
+ /**
+ * A reportable that only reports its name. Does no actual work.
+ */
+ static class TestingReportable implements Reportable {
+
+ @Override
+ public void run(RatReport report) throws RatException {
+ // does nothing
+ }
+
+ @Override
+ public DocumentName name() {
+ return DocumentName.builder().setBaseName("").setName("TestingReportable").build();
+ }
+ }
}
diff --git a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
index bd9e4fd63..12fe7aa45 100644
--- a/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
+++ b/apache-rat-core/src/test/java/org/apache/rat/ReporterOptionsProvider.java
@@ -65,6 +65,7 @@
import static org.apache.rat.commandline.Arg.HELP_LICENSES;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Fail.fail;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@@ -133,9 +134,9 @@ private void validateNoArgSetup() throws IOException, RatException {
try {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
+ Reporter.Output output = reporter.execute();
ClaimValidator validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).isEmpty();
+ assertThat(validator.listIssues(output.getStatistic())).isEmpty();
} finally {
DefaultLog.setInstance(null);
}
@@ -160,8 +161,8 @@ private void editLicenseTest(final Option option) {
FileUtils.delete(resultFile);
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic).isNotNull();
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic()).isNotNull();
String contents = String.join("\n", IOUtils.readLines(new FileReader(testFile)));
assertThat(contents).isEqualTo("class NoLicense {}");
assertThat(resultFile).exists();
@@ -214,9 +215,9 @@ private void execLicensesDeniedTest(final Option option, final String[] args) {
ReportConfiguration config = generateConfig(ImmutablePair.of(option, args));
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
+ Reporter.Output output = reporter.execute();
ClaimValidator validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).containsExactly("UNAPPROVED");
+ assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
});
}
@@ -243,14 +244,8 @@ private void noDefaultsTest(final Option option) {
ReportConfiguration config = generateConfig(ImmutablePair.of(option, null));
Reporter reporter = new Reporter(config);
- try {
- reporter.execute();
- fail("Should have thrown exception");
- } catch (RatException e) {
- ClaimStatistic claimStatistic = reporter.getClaimsStatistic();
- ClaimValidator validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).containsExactlyInAnyOrder("DOCUMENT_TYPES", "LICENSE_CATEGORIES", "LICENSE_NAMES", "STANDARDS");
- }
+ assertThatThrownBy(reporter::execute)
+ .isInstanceOf(RatException.class);
});
}
@@ -276,16 +271,16 @@ protected void counterMaxTest() {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
+ Reporter.Output output = reporter.execute();
ClaimValidator validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).containsExactly("UNAPPROVED");
+ assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
arg[0] = "Unapproved:1";
config = generateConfig(ImmutablePair.of(option, arg));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
+ output = reporter.execute();
validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).isEmpty();
+ assertThat(validator.listIssues(output.getStatistic())).isEmpty();
});
}
@@ -301,16 +296,16 @@ protected void counterMinTest() {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
+ Reporter.Output output = reporter.execute();
ClaimValidator validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).containsExactly("UNAPPROVED");
+ assertThat(validator.listIssues(output.getStatistic())).containsExactly("UNAPPROVED");
arg[0] = "Unapproved:1";
config = generateConfig(ImmutablePair.of(option, arg));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
+ output = reporter.execute();
validator = config.getClaimValidator();
- assertThat(validator.listIssues(claimStatistic)).isEmpty();
+ assertThat(validator.listIssues(output.getStatistic())).isEmpty();
});
}
@@ -329,16 +324,16 @@ private void execExcludeTest(final Option option, final String[] args, final boo
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 1 : 0);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 1 : 0);
// filter out source
config = generateConfig(ImmutablePair.of(option, args));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3);
});
}
@@ -381,16 +376,16 @@ protected void inputExcludeSizeTest() {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(0);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
// filter out source
config = generateConfig(ImmutablePair.of(option, args));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
});
}
@@ -415,15 +410,15 @@ protected void inputExcludeStdTest() {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(4);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(5);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(4);
config = generateConfig(ImmutablePair.of(option, args));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
});
}
@@ -471,16 +466,16 @@ protected void inputExcludeParsedScmTest() {
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(11);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(11);
// .gitignore is ignored by default as it is hidden but not counted
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(0);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
config = generateConfig(ImmutablePair.of(option, args));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(8);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(8);
});
}
@@ -499,25 +494,25 @@ private void execIncludeTest(final Option option, final String[] args, boolean a
ReportConfiguration config = generateConfig(Collections.emptyList());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 1 : 0);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(4);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 1 : 0);
// verify exclude removes most files.
config = generateConfig(ImmutablePair.of(excludeOption, EXCLUDE_ARGS));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
// .gitignore is ignored by default as it is hidden but not counted
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 4 : 3);
- // verify include pust them back
+ // verify include put them back
config = generateConfig(ImmutablePair.of(option, args), ImmutablePair.of(excludeOption, EXCLUDE_ARGS));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
// .gitignore is ignored by default as it is hidden but not counted
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 2 : 1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(addIgnored ? 2 : 1);
});
}
@@ -569,15 +564,15 @@ protected void inputIncludeStdTest() {
ReportConfiguration config = generateConfig(Collections.singletonList(excludes));
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(5);
config = generateConfig(excludes, ImmutablePair.of(option, args));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(7);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(7);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(1);
});
}
@@ -594,15 +589,15 @@ protected void inputSourceTest() {
ReportConfiguration config = generateConfig();
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(0);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(3);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
config = generateConfig(ImmutablePair.of(option, new String[]{inputFile.getAbsolutePath()}));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.IGNORED)).isEqualTo(0);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.IGNORED)).isZero();
});
}
@@ -624,18 +619,18 @@ private void execLicenseFamiliesApprovedTest(final Option option, final String[]
ReportConfiguration config = addCatzLicense(generateConfig());
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
+ Reporter.Output output = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(0);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
config = addCatzLicense(generateConfig(arg1));
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
});
}
@@ -658,23 +653,21 @@ private void execLicenseFamiliesDeniedTest(final Option option, final String[] a
assertDoesNotThrow(() -> {
configureSourceDir(option);
-
- // write the catz licensed text file
writeFile("bsd.txt", "SPDX-License-Identifier: BSD-3-Clause");
ReportConfiguration config = generateConfig();
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
config = generateConfig(arg1);
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(0);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isZero();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
});
}
@@ -704,26 +697,26 @@ private void configTest(final Option option) {
ReportConfiguration config = generateConfig();
Reporter reporter = new Reporter(config);
- ClaimStatistic claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
+ Reporter.Output output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(1);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(1);
config = generateConfig(arg1);
reporter = new Reporter(config);
- claimStatistic = reporter.execute();
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(2);
- assertThat(claimStatistic.getCounter(ClaimStatistic.Counter.UNAPPROVED)).isEqualTo(0);
+ output = reporter.execute();
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.STANDARDS)).isEqualTo(2);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.APPROVED)).isEqualTo(2);
+ assertThat(output.getStatistic().getCounter(ClaimStatistic.Counter.UNAPPROVED)).isZero();
Pair